diff --git a/src/86box.c b/src/86box.c index 66b9dc88d..25aeeae47 100644 --- a/src/86box.c +++ b/src/86box.c @@ -253,6 +253,8 @@ struct accelKey def_acc_keys[NUM_ACCELS] = { .seq="Ctrl+Alt+M" } }; +char vmm_path[1024] = { '\0'}; /* TEMPORARY - VM manager path to scan for VMs */ +int vmm_enabled = 0; /* Statistics. */ extern int mmuflush; @@ -600,8 +602,8 @@ pc_show_usage(char *s) #ifdef _WIN32 "-D or --debug\t\t\t- force debug output logging\n" #endif -#if 0 - "-E or --nographic\t\t- forces the old behavior\n" +#if 1 + "-E or --vmmpath\t\t- vm manager path\n" #endif "-F or --fullscreen\t\t- start in fullscreen mode\n" "-G or --lang langid\t\t- start with specified language\n" @@ -637,7 +639,7 @@ pc_show_usage(char *s) ui_msgbox(MBX_ANSI | ((s == NULL) ? MBX_INFO : MBX_WARNING), p); #else if (s == NULL) - pclog(p); + pclog("%s", p); else ui_msgbox(MBX_ANSI | MBX_WARNING, p); #endif @@ -734,13 +736,18 @@ usage: } else if (!strcasecmp(argv[c], "--debug") || !strcasecmp(argv[c], "-D")) { force_debug = 1; #endif -#ifdef ENABLE_NG - } else if (!strcasecmp(argv[c], "--nographic") || !strcasecmp(argv[c], "-E")) { - /* Currently does nothing, but if/when we implement a built-in manager, - it's going to force the manager not to run, allowing the old usage - without parameter. */ - ng = 1; -#endif +//#ifdef ENABLE_NG + } else if (!strcasecmp(argv[c], "--vmmpath") || + !strcasecmp(argv[c], "-E")) { + /* Using this variable for vm manager path + Temporary solution!*/ + if ((c+1) == argc) goto usage; + char *vp = argv[++c]; + if ((strlen(vp) + 1) >= sizeof(vmm_path)) + memcpy(vmm_path, vp, sizeof(vmm_path)); + else + memcpy(vmm_path, vp, strlen(vp) + 1); + //#endif } else if (!strcasecmp(argv[c], "--fullscreen") || !strcasecmp(argv[c], "-F")) { start_in_fullscreen = 1; } else if (!strcasecmp(argv[c], "--logfile") || !strcasecmp(argv[c], "-L")) { @@ -1027,6 +1034,10 @@ usage: } pclog("# Configuration file: %s\n#\n\n", cfg_path); + if (strlen(vmm_path) != 0) { + vmm_enabled = 1; + pclog("# VM Manager enabled. Path: %s\n", vmm_path); + } /* * We are about to read the configuration file, which MAY * put data into global variables (the hard- and floppy diff --git a/src/chipset/CMakeLists.txt b/src/chipset/CMakeLists.txt index 7817ac052..d61b5c53d 100644 --- a/src/chipset/CMakeLists.txt +++ b/src/chipset/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(chipset OBJECT 82c100.c + acc2036.c acc2168.c cs8220.c cs8230.c @@ -48,6 +49,7 @@ add_library(chipset OBJECT opti291.c opti391.c opti495.c + opti498.c opti499.c opti602.c opti822.c diff --git a/src/chipset/acc2036.c b/src/chipset/acc2036.c new file mode 100644 index 000000000..225c22813 --- /dev/null +++ b/src/chipset/acc2036.c @@ -0,0 +1,346 @@ +/* + * 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 the ACC 2036 chipset. + * + * Authors: Miran Grca, + * + * Copyright 2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/machine.h> +#include <86box/mem.h> +#include <86box/port_92.h> +#include <86box/plat_fallthrough.h> +#include <86box/plat_unused.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/chipset.h> + +typedef struct { + uint32_t virt; + uint32_t phys; + + mem_mapping_t mapping; +} ram_page_t; + +typedef struct { + uint8_t reg; + uint8_t regs[32]; + + ram_page_t ram_mid_pages[24]; + ram_page_t ems_pages[4]; +} acc2036_t; + +static uint8_t +acc2036_mem_read(uint32_t addr, void *priv) +{ + ram_page_t *dev = (ram_page_t *) priv; + uint8_t ret = 0xff; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ret = ram[addr]; + + return ret; +} + +static uint16_t +acc2036_mem_readw(uint32_t addr, void *priv) +{ + ram_page_t *dev = (ram_page_t *) priv; + uint16_t ret = 0xffff; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ret = *(uint16_t *) &(ram[addr]); + + return ret; +} + +static void +acc2036_mem_write(uint32_t addr, uint8_t val, void *priv) +{ + ram_page_t *dev = (ram_page_t *) priv; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + ram[addr] = val; +} + +static void +acc2036_mem_writew(uint32_t addr, uint16_t val, void *priv) +{ + ram_page_t *dev = (ram_page_t *) priv; + + addr = (addr - dev->virt) + dev->phys; + + if (addr < (mem_size << 10)) + *(uint16_t *) &(ram[addr]) = val; +} + +static void +acc2036_recalc(acc2036_t *dev) +{ + uint32_t ems_bases[4] = { 0x000c0000, 0x000c8000, 0x000d0000, 0x000e0000 }; + + int start_i = (ems_bases[dev->regs[0x0c] & 0x03] - 0x000a0000) >> 14; + int end_i = start_i + 3; + + for (int i = 0; i < 24; i++) { + ram_page_t *rp = &dev->ram_mid_pages[i]; + mem_mapping_disable(&rp->mapping); + } + + for (int i = 0; i < 4; i++) { + ram_page_t *ep = &dev->ems_pages[i]; + mem_mapping_disable(&ep->mapping); + } + + for (int i = 0; i < 24; i++) { + ram_page_t *rp = &dev->ram_mid_pages[i]; + + if ((dev->regs[0x03] & 0x08) && (i >= start_i) && (i <= end_i)) { + /* EMS */ + ram_page_t *ep = &dev->ems_pages[i - start_i]; + + mem_mapping_disable(&rp->mapping); + mem_mapping_set_addr(&ep->mapping, ep->virt, 0x000040000); + mem_mapping_set_exec(&ep->mapping, ram + ep->phys); + mem_set_mem_state_both(ep->virt, 0x00004000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } else { + int master_write; + int master_read; + int bit; + int ew_flag; + int er_flag; + int flags; + uint8_t val; + + mem_mapping_set_addr(&rp->mapping, rp->virt, 0x000040000); + mem_mapping_set_exec(&rp->mapping, ram + rp->phys); + + if ((i >= 8) && (i <= 15)) { + /* 0C0000-0DFFFF */ + master_write = dev->regs[0x02] & 0x08; + master_read = dev->regs[0x02] & 0x04; + bit = ((i - 8) >> 1); + val = dev->regs[0x0d] & (1 << bit); + if (i >= 12) { + ew_flag = (dev->regs[0x07] & 0x80) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL; + er_flag = (dev->regs[0x07] & 0x80) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL; + } else { + ew_flag = (dev->regs[0x07] & 0x40) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL; + er_flag = (dev->regs[0x07] & 0x40) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL; + } + flags = (val && master_write) ? MEM_WRITE_INTERNAL : ew_flag; + flags |= (val && master_read) ? MEM_READ_INTERNAL : er_flag; + mem_set_mem_state_both(rp->virt, 0x00004000, flags); + } else if (i > 15) { + /* 0E0000-0FFFFF */ + master_write = dev->regs[0x02] & 0x02; + master_read = dev->regs[0x02] & 0x01; + bit = (((i - 8) >> 2) + 2); + val = dev->regs[0x0c] & (1 << bit); + if (i >= 20) { + ew_flag = MEM_WRITE_EXTANY; + er_flag = MEM_READ_EXTANY; + } else { + ew_flag = (dev->regs[0x0c] & 0x10) ? MEM_WRITE_EXTANY : MEM_WRITE_EXTERNAL; + er_flag = (dev->regs[0x0c] & 0x10) ? MEM_READ_EXTANY : MEM_READ_EXTERNAL; + } + flags = (val && master_write) ? MEM_WRITE_INTERNAL : ew_flag; + flags |= (val && master_read) ? MEM_READ_INTERNAL : er_flag; + mem_set_mem_state_both(rp->virt, 0x00004000, flags); + } + } + } + + if (dev->regs[0x00] & 0x40) + mem_set_mem_state_both(0x00fe0000, 0x00010000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else + mem_set_mem_state_both(0x00fe0000, 0x00010000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + for (int i = 0x01; i <= 0x06; i++) { + uint32_t base = 0x00fe0000 - (i * 0x00010000); + + if (dev->regs[i] & 0x40) + mem_set_mem_state_both(base, 0x00008000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else + mem_set_mem_state_both(base, 0x00008000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + if (dev->regs[i] & 0x80) + mem_set_mem_state_both(base + 0x00008000, 0x00008000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + else + mem_set_mem_state_both(base + 0x00008000, 0x00008000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + + mem_remap_top(0); + if (dev->regs[0x03] & 0x10) { + if (dev->regs[0x02] & 0x0c) + mem_remap_top(128); + else if (dev->regs[0x02] & 0x03) + mem_remap_top(256); + else + mem_remap_top(384); + } + + flushmmucache_nopc(); +} + +static uint8_t +acc2036_in(uint16_t port, void *priv) { + acc2036_t *dev = (acc2036_t *) priv; + uint8_t reg = dev->reg - 0x20; + uint8_t ret = 0xff; + + if (port & 0x0001) switch (dev->reg) { + default: + break; + case 0x20 ... 0x2e: + case 0x31 ... 0x3f: + ret = dev->regs[reg]; + break; + } else + ret = dev->reg; + + return ret; +} + +static void +acc2036_out(uint16_t port, uint8_t val, void *priv) { + acc2036_t *dev = (acc2036_t *) priv; + uint8_t reg = dev->reg - 0x20; + + if (port & 0x0001) switch (dev->reg) { + default: + break; + case 0x20 ... 0x23: + dev->regs[reg] = val; + acc2036_recalc(dev); + break; + case 0x24 ... 0x2b: + dev->regs[reg] = val; + dev->ems_pages[(reg - 0x04) >> 1].phys = ((dev->regs[reg & 0xfe] & 0x1f) << 19) | + ((dev->regs[reg | 0x01] & 0x1f) << 14); + acc2036_recalc(dev); + break; + case 0x2c: case 0x2d: + dev->regs[reg] = val; + acc2036_recalc(dev); + break; + case 0x2e: + dev->regs[reg] = val | 0x10; + break; + case 0x31: + dev->regs[reg] = val; + mem_a20_alt = (val & 0x01); + mem_a20_recalc(); + flushmmucache(); + if (val & 0x02) { + softresetx86(); /* Pulse reset! */ + cpu_set_edx(); + flushmmucache(); + } + break; + case 0x32 ... 0x3f: + dev->regs[reg] = val; + break; + } else + dev->reg = val; +} + +static void +acc2036_close(void *priv) +{ + acc2036_t *dev = (acc2036_t *) priv; + + free(dev); +} + +static void * +acc2036_init(UNUSED(const device_t *info)) +{ + acc2036_t *dev = (acc2036_t *) calloc(1, sizeof(acc2036_t)); + + for (int i = 0; i < 24; i++) { + ram_page_t *rp = &dev->ram_mid_pages[i]; + + rp->virt = 0x000a0000 + (i << 14); + rp->phys = 0x000a0000 + (i << 14); + mem_mapping_add(&rp->mapping, rp->virt, 0x00004000, + acc2036_mem_read, acc2036_mem_readw, NULL, + acc2036_mem_write, acc2036_mem_writew, NULL, + ram + rp->phys, MEM_MAPPING_INTERNAL, rp); + } + + for (int i = 0; i < 4; i++) { + ram_page_t *ep = &dev->ems_pages[i]; + + ep->virt = 0x000d0000 + (i << 14); + ep->phys = 0x00000000 + (i << 14); + mem_mapping_add(&ep->mapping, ep->virt, 0x00004000, + acc2036_mem_read, acc2036_mem_readw, NULL, + acc2036_mem_write, acc2036_mem_writew, NULL, + ram + ep->phys, MEM_MAPPING_INTERNAL, ep); + mem_mapping_disable(&ep->mapping); + } + + mem_mapping_disable(&ram_mid_mapping); + + dev->regs[0x00] = 0x02; + dev->regs[0x0e] = 0x10; + dev->regs[0x11] = 0x01; + dev->regs[0x13] = 0x40; + dev->regs[0x15] = 0x40; + dev->regs[0x17] = 0x40; + dev->regs[0x19] = 0x40; + dev->regs[0x1b] = 0x40; + dev->regs[0x1c] = 0x22; + dev->regs[0x1d] = 0xc4; + dev->regs[0x1f] = 0x30; + acc2036_recalc(dev); + + mem_a20_alt = 0x01; + mem_a20_recalc(); + flushmmucache(); + + io_sethandler(0x00f2, 0x0002, + acc2036_in, NULL, NULL, acc2036_out, NULL, NULL, dev); + + device_add(&port_92_device); + + return dev; +} + +const device_t acc2036_device = { + .name = "ACC 2036", + .internal_name = "acc2036", + .flags = 0, + .local = 0, + .init = acc2036_init, + .close = acc2036_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/opti283.c b/src/chipset/opti283.c index 395ad4212..81780cf10 100644 --- a/src/chipset/opti283.c +++ b/src/chipset/opti283.c @@ -16,6 +16,7 @@ * Copyright 2021 Tiseno100. * Copyright 2021 Miran Grca. */ +#include #include #include #include @@ -158,7 +159,20 @@ opti283_shadow_recalc(opti283_t *dev) rom = dev->regs[0x11] & (1 << ((i >> 2) + 4)); opti283_log("OPTI 283: %i/%08X: %i, %i, %i\n", i, base, (i >= 4) ? (1 << (i - 4)) : (1 << (i + 4)), (1 << (i >> 2)), (1 << ((i >> 2) + 4))); - if (sh_enable && rom) { + if (sh_copy) { + if (base >= 0x000e0000) + shadowbios_write |= 1; + if (base >= 0x000d0000) + dev->shadow_high |= 1; + + if (base >= 0xe0000) { + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + opti283_log("OPTI 283: %08X-%08X READ_EXTANY, WRITE_INTERNAL\n", base, base + 0x3fff); + } else { + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + opti283_log("OPTI 283: %08X-%08X READ_EXTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff); + } + } else if (sh_enable && rom) { if (base >= 0x000e0000) shadowbios |= 1; if (base >= 0x000d0000) @@ -171,13 +185,8 @@ opti283_shadow_recalc(opti283_t *dev) if (base >= 0x000e0000) shadowbios_write |= 1; - if (sh_copy) { - mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - opti283_log("OPTI 283: %08X-%08X READ_INTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff); - } else { - mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - opti283_log("OPTI 283: %08X-%08X READ_INTERNAL, WRITE_EXTERNAL\n", base, base + 0x3fff); - } + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + opti283_log("OPTI 283: %08X-%08X READ_INTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff); } } else { if (base >= 0xe0000) { @@ -239,9 +248,21 @@ opti283_write(uint16_t addr, uint8_t val, void *priv) dev->regs[dev->index] = (dev->regs[dev->index] & 0x80) | (val & 0x7f); break; - case 0x14: + case 0x14: { + double bus_clk; + switch (val & 0x01) { + default: + case 0x00: + bus_clk = cpu_busspeed / 6.0; + break; + case 0x01: + bus_clk = cpu_busspeed / 4.0; + break; + } + cpu_set_isa_speed((int) round(bus_clk)); reset_on_hlt = !!(val & 0x40); fallthrough; + } case 0x11: case 0x12: case 0x13: @@ -310,6 +331,8 @@ opti283_init(UNUSED(const device_t *info)) opti283_shadow_recalc(dev); + cpu_set_isa_speed((int) round(cpu_busspeed / 6.0)); + device_add(&port_92_device); return dev; diff --git a/src/chipset/opti495.c b/src/chipset/opti495.c index aa4e4b4c5..8521dbd17 100644 --- a/src/chipset/opti495.c +++ b/src/chipset/opti495.c @@ -8,14 +8,13 @@ * * Implementation of the OPTi 82C493/82C495 chipset. * - * - * * Authors: Tiseno100, * Miran Grca, * * Copyright 2008-2020 Tiseno100. * Copyright 2016-2020 Miran Grca. */ +#include #include #include #include @@ -28,6 +27,7 @@ #include <86box/io.h> #include <86box/device.h> #include <86box/mem.h> +#include <86box/plat_fallthrough.h> #include <86box/port_92.h> #include <86box/chipset.h> @@ -166,6 +166,27 @@ opti495_write(uint16_t addr, uint8_t val, void *priv) case 0x26: opti495_recalc(dev); break; + + case 0x25: { + double bus_clk; + switch (val & 0x03) { + default: + case 0x00: + bus_clk = cpu_busspeed / 6.0; + break; + case 0x01: + bus_clk = cpu_busspeed / 4.0; + break; + case 0x02: + bus_clk = cpu_busspeed / 3.0; + break; + case 0x03: + bus_clk = (cpu_busspeed * 2.0) / 5.0; + break; + } + cpu_set_isa_speed((int) round(bus_clk)); + break; + } } } @@ -259,6 +280,8 @@ opti495_init(const device_t *info) io_sethandler(0x00e1, 0x0002, opti495_read, NULL, NULL, opti495_write, NULL, NULL, dev); + cpu_set_isa_speed((int) round(cpu_busspeed / 6.0)); + return dev; } @@ -276,11 +299,25 @@ const device_t opti493_device = { .config = NULL }; -const device_t opti495_device = { +const device_t opti495slc_device = { .name = "OPTi 82C495", - .internal_name = "opti495", + .internal_name = "opti495slc", .flags = 0, - .local = OPTI495XLC, + .local = OPTI495SLC, + .init = opti495_init, + .close = opti495_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t opti495sx_device = { + .name = "OPTi 82C495SX", + .internal_name = "opti495sx", + .flags = 0, + .local = OPTI495SX, .init = opti495_init, .close = opti495_close, .reset = NULL, diff --git a/src/chipset/opti498.c b/src/chipset/opti498.c new file mode 100644 index 000000000..2d3dc6709 --- /dev/null +++ b/src/chipset/opti498.c @@ -0,0 +1,360 @@ +/* + * 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 the OPTi 82C498 chipset. + * + * Authors: Miran Grca, + * + * Copyright 2025 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/device.h> +#include <86box/mem.h> +#include <86box/plat_fallthrough.h> +#include <86box/plat_unused.h> +#include <86box/port_92.h> +#include <86box/chipset.h> + +#ifdef ENABLE_OPTI498_LOG +int opti498_do_log = ENABLE_OPTI498_LOG; + +static void +opti498_log(const char *fmt, ...) +{ + va_list ap; + + if (opti498_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define opti498_log(fmt, ...) +#endif + +typedef struct mem_remapping_t { + uint32_t phys; + uint32_t virt; +} mem_remapping_t; + +typedef struct opti498_t { + uint8_t index; + /* 0x30 for 496/497, 0x70 for 498. */ + uint8_t reg_base; + uint8_t shadow_high; + uint8_t regs[256]; + mem_remapping_t mem_remappings[2]; + mem_mapping_t mem_mappings[2]; +} opti498_t; + +static uint8_t +opti498_read_remapped_ram(uint32_t addr, void *priv) +{ + const mem_remapping_t *dev = (mem_remapping_t *) priv; + + return mem_read_ram((addr - dev->virt) + dev->phys, priv); +} + +static uint16_t +opti498_read_remapped_ramw(uint32_t addr, void *priv) +{ + const mem_remapping_t *dev = (mem_remapping_t *) priv; + + return mem_read_ramw((addr - dev->virt) + dev->phys, priv); +} + +static uint32_t +opti498_read_remapped_raml(uint32_t addr, void *priv) +{ + const mem_remapping_t *dev = (mem_remapping_t *) priv; + + return mem_read_raml((addr - dev->virt) + dev->phys, priv); +} + +static void +opti498_write_remapped_ram(uint32_t addr, uint8_t val, void *priv) +{ + const mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_ram((addr - dev->virt) + dev->phys, val, priv); +} + +static void +opti498_write_remapped_ramw(uint32_t addr, uint16_t val, void *priv) +{ + const mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_ramw((addr - dev->virt) + dev->phys, val, priv); +} + +static void +opti498_write_remapped_raml(uint32_t addr, uint32_t val, void *priv) +{ + const mem_remapping_t *dev = (mem_remapping_t *) priv; + + mem_write_raml((addr - dev->virt) + dev->phys, val, priv); +} + +static void +opti498_shadow_recalc(opti498_t *dev) +{ + uint32_t base; + uint32_t rbase; + uint8_t sh_enable; + uint8_t sh_mode; + uint8_t rom; + uint8_t sh_copy; + + shadowbios = shadowbios_write = 0; + dev->shadow_high = 0; + + opti498_log("OPTI 498: %02X %02X %02X %02X\n", dev->regs[0x02], dev->regs[0x03], dev->regs[0x04], dev->regs[0x05]); + + if (dev->regs[0x02] & 0x80) { + if (dev->regs[0x04] & 0x02) { + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + opti498_log("OPTI 498: F0000-FFFFF READ_EXTANY, WRITE_EXTANY\n"); + } else { + shadowbios_write = 1; + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + opti498_log("OPTI 498: F0000-FFFFF READ_EXTANY, WRITE_INTERNAL\n"); + } + } else { + shadowbios = 1; + mem_set_mem_state_both(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + opti498_log("OPTI 498: F0000-FFFFF READ_INTERNAL, WRITE_DISABLED\n"); + } + + sh_copy = dev->regs[0x02] & 0x08; + for (uint8_t i = 0; i < 12; i++) { + base = 0xc0000 + (i << 14); + if (i >= 4) + sh_enable = dev->regs[0x03] & (1 << (i - 4)); + else + sh_enable = dev->regs[0x04] & (1 << (i + 4)); + sh_mode = dev->regs[0x02] & (1 << (i >> 2)); + rom = dev->regs[0x02] & (1 << ((i >> 2) + 4)); + opti498_log("OPTI 498: %i/%08X: %i, %i, %i\n", i, base, (i >= 4) ? (1 << (i - 4)) : (1 << (i + 4)), (1 << (i >> 2)), (1 << ((i >> 2) + 4))); + + if (sh_copy) { + if (base >= 0x000e0000) + shadowbios_write |= 1; + if (base >= 0x000d0000) + dev->shadow_high |= 1; + + if (base >= 0xe0000) { + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + opti498_log("OPTI 498: %08X-%08X READ_EXTANY, WRITE_INTERNAL\n", base, base + 0x3fff); + } else { + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + opti498_log("OPTI 498: %08X-%08X READ_EXTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff); + } + } else if (sh_enable && rom) { + if (base >= 0x000e0000) + shadowbios |= 1; + if (base >= 0x000d0000) + dev->shadow_high |= 1; + + if (sh_mode) { + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + opti498_log("OPTI 498: %08X-%08X READ_INTERNAL, WRITE_DISABLED\n", base, base + 0x3fff); + } else { + if (base >= 0x000e0000) + shadowbios_write |= 1; + + mem_set_mem_state_both(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + opti498_log("OPTI 498: %08X-%08X READ_INTERNAL, WRITE_INTERNAL\n", base, base + 0x3fff); + } + } else { + if (base >= 0xe0000) { + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTANY | MEM_WRITE_DISABLED); + opti498_log("OPTI 498: %08X-%08X READ_EXTANY, WRITE_DISABLED\n", base, base + 0x3fff); + } else { + mem_set_mem_state_both(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_DISABLED); + opti498_log("OPTI 498: %08X-%08X READ_EXTERNAL, WRITE_DISABLED\n", base, base + 0x3fff); + } + } + } + + rbase = ((uint32_t) (dev->regs[0x05] & 0x3f)) << 20; + + if (rbase > 0) { + dev->mem_remappings[0].virt = rbase; + mem_mapping_set_addr(&dev->mem_mappings[0], rbase, 0x00020000); + + if (!dev->shadow_high) { + rbase += 0x00020000; + dev->mem_remappings[1].virt = rbase; + mem_mapping_set_addr(&dev->mem_mappings[1], rbase, 0x00020000); + } else + mem_mapping_disable(&dev->mem_mappings[1]); + } else { + mem_mapping_disable(&dev->mem_mappings[0]); + mem_mapping_disable(&dev->mem_mappings[1]); + } + + flushmmucache_nopc(); +} + +static void +opti498_write(uint16_t addr, uint8_t val, void *priv) +{ + opti498_t *dev = (opti498_t *) priv; + uint8_t reg = dev->index - dev->reg_base; + + switch (addr) { + default: + break; + + case 0x22: + dev->index = val; + break; + + case 0x24: + opti498_log("OPTi 498: dev->regs[%02x] = %02x\n", dev->index, val); + + if ((reg >= 0x00) && (reg <= 0x0b)) switch (reg) { + default: + break; + + case 0x00: + dev->regs[reg] = (dev->regs[reg] & 0xc0) | (val & 0x3f); + break; + + case 0x01: + case 0x07 ... 0x0b: + dev->regs[reg] = val; + break; + + case 0x02: + case 0x03: + case 0x04: + case 0x05: + dev->regs[reg] = val; + opti498_shadow_recalc(dev); + break; + + case 0x06: { + double bus_clk; + dev->regs[reg] = val; + switch (val & 0x03) { + default: + case 0x00: + bus_clk = cpu_busspeed / 8.0; + break; + case 0x01: + bus_clk = cpu_busspeed / 6.0; + break; + case 0x02: + bus_clk = cpu_busspeed / 5.0; + break; + case 0x03: + bus_clk = cpu_busspeed / 4.0; + break; + } + cpu_set_isa_speed((int) round(bus_clk)); + reset_on_hlt = !!(val & 0x40); + break; + } + } + + dev->index = 0xff; + break; + } +} + +static uint8_t +opti498_read(uint16_t addr, void *priv) +{ + opti498_t *dev = (opti498_t *) priv; + uint8_t reg = dev->index - dev->reg_base; + uint8_t ret = 0xff; + + if (addr == 0x24) { + if ((reg >= 0x00) && (reg <= 0x0b)) + ret = dev->regs[reg]; + + dev->index = 0xff; + } + + return ret; +} + +static void +opti498_close(void *priv) +{ + opti498_t *dev = (opti498_t *) priv; + + free(dev); +} + +static void * +opti498_init(UNUSED(const device_t *info)) +{ + opti498_t *dev = (opti498_t *) calloc(1, sizeof(opti498_t)); + + dev->reg_base = info->local & 0xff; + + io_sethandler(0x0022, 0x0001, opti498_read, NULL, NULL, opti498_write, NULL, NULL, dev); + io_sethandler(0x0024, 0x0001, opti498_read, NULL, NULL, opti498_write, NULL, NULL, dev); + + dev->regs[0x00] = 0x1f; + dev->regs[0x01] = 0x8f; + dev->regs[0x02] = 0xf0; + dev->regs[0x07] = 0x70; + dev->regs[0x09] = 0x70; + + dev->mem_remappings[0].phys = 0x000a0000; + dev->mem_remappings[1].phys = 0x000d0000; + + mem_mapping_add(&dev->mem_mappings[0], 0, 0x00020000, + opti498_read_remapped_ram, opti498_read_remapped_ramw, opti498_read_remapped_raml, + opti498_write_remapped_ram, opti498_write_remapped_ramw, opti498_write_remapped_raml, + &ram[dev->mem_remappings[0].phys], MEM_MAPPING_INTERNAL, &dev->mem_remappings[0]); + mem_mapping_disable(&dev->mem_mappings[0]); + + mem_mapping_add(&dev->mem_mappings[1], 0, 0x00020000, + opti498_read_remapped_ram, opti498_read_remapped_ramw, opti498_read_remapped_raml, + opti498_write_remapped_ram, opti498_write_remapped_ramw, opti498_write_remapped_raml, + &ram[dev->mem_remappings[1].phys], MEM_MAPPING_INTERNAL, &dev->mem_remappings[1]); + mem_mapping_disable(&dev->mem_mappings[1]); + + opti498_shadow_recalc(dev); + + cpu_set_isa_speed((int) round(cpu_busspeed / 8.0)); + + device_add(&port_92_device); + + return dev; +} + +const device_t opti498_device = { + .name = "OPTi 82C498", + .internal_name = "opti498", + .flags = 0, + .local = 0x70, + .init = opti498_init, + .close = opti498_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c index d54e8184e..383b8e3e2 100644 --- a/src/chipset/opti499.c +++ b/src/chipset/opti499.c @@ -16,6 +16,7 @@ * Copyright 2008-2020 Tiseno100. * Copyright 2016-2020 Miran Grca. */ +#include #include #include #include @@ -148,9 +149,28 @@ opti499_write(uint16_t addr, uint8_t val, void *priv) default: break; - case 0x20: + case 0x20: { + double coeff = (val & 0x10) ? 1.0 : 2.0; + double bus_clk; + switch (dev->regs[0x25] & 0x03) { + default: + case 0x00: + bus_clk = (cpu_busspeed * coeff) / 6.0; + break; + case 0x01: + bus_clk = (cpu_busspeed * coeff) / 5.0; + break; + case 0x02: + bus_clk = (cpu_busspeed * coeff) / 4.0; + break; + case 0x03: + bus_clk = (cpu_busspeed * coeff) / 3.0; + break; + } + cpu_set_isa_speed((int) round(bus_clk)); reset_on_hlt = !(val & 0x02); break; + } case 0x21: cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); @@ -163,6 +183,28 @@ opti499_write(uint16_t addr, uint8_t val, void *priv) case 0x2d: opti499_recalc(dev); break; + + case 0x25: { + double coeff = (dev->regs[0x20] & 0x10) ? 1.0 : 2.0; + double bus_clk; + switch (val & 0x03) { + default: + case 0x00: + bus_clk = (cpu_busspeed * coeff) / 8.0; + break; + case 0x01: + bus_clk = (cpu_busspeed * coeff) / 6.0; + break; + case 0x02: + bus_clk = (cpu_busspeed * coeff) / 5.0; + break; + case 0x03: + bus_clk = (cpu_busspeed * coeff) / 4.0; + break; + } + cpu_set_isa_speed((int) round(bus_clk)); + break; + } } } @@ -229,6 +271,8 @@ opti499_reset(void *priv) cpu_update_waitstates(); opti499_recalc(dev); + + cpu_set_isa_speed((int) round((cpu_busspeed * 2.0) / 6.0)); } static void diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c index cb55ef2a7..16b324963 100644 --- a/src/chipset/opti895.c +++ b/src/chipset/opti895.c @@ -16,6 +16,7 @@ * Copyright 2008-2020 Tiseno100. * Copyright 2016-2020 Miran Grca. */ +#include #include #include #include @@ -182,6 +183,27 @@ opti895_write(uint16_t addr, uint8_t val, void *priv) smram_state_change(dev->smram, 0, !!(val & 0x80)); break; + case 0x25: { + double bus_clk; + switch (val & 0x03) { + default: + case 0x00: + bus_clk = cpu_busspeed / 6.0; + break; + case 0x01: + bus_clk = cpu_busspeed / 5.0; + break; + case 0x02: + bus_clk = cpu_busspeed / 4.0; + break; + case 0x03: + bus_clk = cpu_busspeed / 3.0; + break; + } + cpu_set_isa_speed((int) round(bus_clk)); + break; + } + case 0xe0: if (!(val & 0x01)) dev->forced_green = 0; @@ -294,6 +316,8 @@ opti895_init(const device_t *info) smram_enable(dev->smram, 0x00030000, 0x000b0000, 0x00010000, 0, 1); + cpu_set_isa_speed((int) round(cpu_busspeed / 6.0)); + return dev; } diff --git a/src/device/isarom.c b/src/device/isarom.c index 238314c87..f742a9eae 100644 --- a/src/device/isarom.c +++ b/src/device/isarom.c @@ -212,7 +212,7 @@ isarom_init(const device_t *info) static const device_config_t isarom_config[] = { { .name = "bios_fn", - .description = "BIOS File", + .description = "BIOS file", .type = CONFIG_FNAME, .default_string = NULL, .default_int = 0, @@ -234,7 +234,7 @@ static const device_config_t isarom_config[] = { }, { .name = "bios_size", - .description = "BIOS Size:", + .description = "BIOS size", .type = CONFIG_INT, .default_string = NULL, .default_int = 8192, @@ -260,7 +260,7 @@ static const device_config_t isarom_config[] = { static const device_config_t isarom_dual_config[] = { { .name = "bios_fn", - .description = "BIOS File (ROM #1)", + .description = "BIOS file (ROM #1)", .type = CONFIG_FNAME, .default_string = NULL, .default_int = 0, @@ -271,7 +271,7 @@ static const device_config_t isarom_dual_config[] = { }, { .name = "bios_addr", - .description = "BIOS Address (ROM #1)", + .description = "BIOS address (ROM #1)", .type = CONFIG_HEX20, .default_string = NULL, .default_int = 0x00000, @@ -282,7 +282,7 @@ static const device_config_t isarom_dual_config[] = { }, { .name = "bios_size", - .description = "BIOS Size (ROM #1):", + .description = "BIOS size (ROM #1)", .type = CONFIG_INT, .default_string = NULL, .default_int = 8192, @@ -304,7 +304,7 @@ static const device_config_t isarom_dual_config[] = { }, { .name = "bios_fn2", - .description = "BIOS File (ROM #2)", + .description = "BIOS file (ROM #2)", .type = CONFIG_FNAME, .default_string = NULL, .default_int = 0, @@ -315,7 +315,7 @@ static const device_config_t isarom_dual_config[] = { }, { .name = "bios_addr2", - .description = "BIOS Address (ROM #2)", + .description = "BIOS address (ROM #2)", .type = CONFIG_HEX20, .default_string = NULL, .default_int = 0x00000, @@ -326,7 +326,7 @@ static const device_config_t isarom_dual_config[] = { }, { .name = "bios_size2", - .description = "BIOS Size (ROM #2):", + .description = "BIOS size (ROM #2)", .type = CONFIG_INT, .default_string = NULL, .default_int = 8192, @@ -352,7 +352,7 @@ static const device_config_t isarom_dual_config[] = { static const device_config_t isarom_quad_config[] = { { .name = "bios_fn", - .description = "BIOS File (ROM #1)", + .description = "BIOS file (ROM #1)", .type = CONFIG_FNAME, .default_string = NULL, .default_int = 0, @@ -363,7 +363,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_addr", - .description = "BIOS Address (ROM #1)", + .description = "BIOS address (ROM #1)", .type = CONFIG_HEX20, .default_string = NULL, .default_int = 0x00000, @@ -374,7 +374,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_size", - .description = "BIOS Size (ROM #1):", + .description = "BIOS size (ROM #1)", .type = CONFIG_INT, .default_string = NULL, .default_int = 8192, @@ -396,7 +396,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_fn2", - .description = "BIOS File (ROM #2)", + .description = "BIOS file (ROM #2)", .type = CONFIG_FNAME, .default_string = NULL, .default_int = 0, @@ -407,7 +407,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_addr2", - .description = "BIOS Address (ROM #2)", + .description = "BIOS address (ROM #2)", .type = CONFIG_HEX20, .default_string = NULL, .default_int = 0x00000, @@ -418,7 +418,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_size2", - .description = "BIOS Size (ROM #2):", + .description = "BIOS size (ROM #2)", .type = CONFIG_INT, .default_string = NULL, .default_int = 8192, @@ -440,7 +440,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_fn3", - .description = "BIOS File (ROM #3)", + .description = "BIOS file (ROM #3)", .type = CONFIG_FNAME, .default_string = NULL, .default_int = 0, @@ -451,7 +451,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_addr3", - .description = "BIOS Address (ROM #3)", + .description = "BIOS address (ROM #3)", .type = CONFIG_HEX20, .default_string = NULL, .default_int = 0x00000, @@ -462,7 +462,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_size3", - .description = "BIOS Size (ROM #3):", + .description = "BIOS size (ROM #3)", .type = CONFIG_INT, .default_string = NULL, .default_int = 8192, @@ -484,7 +484,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_fn4", - .description = "BIOS File (ROM #4)", + .description = "BIOS file (ROM #4)", .type = CONFIG_FNAME, .default_string = NULL, .default_int = 0, @@ -495,7 +495,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_addr4", - .description = "BIOS Address (ROM #4)", + .description = "BIOS address (ROM #4)", .type = CONFIG_HEX20, .default_string = NULL, .default_int = 0x00000, @@ -506,7 +506,7 @@ static const device_config_t isarom_quad_config[] = { }, { .name = "bios_size4", - .description = "BIOS Size (ROM #4):", + .description = "BIOS size (ROM #4)", .type = CONFIG_INT, .default_string = NULL, .default_int = 8192, diff --git a/src/device/keyboard_xt.c b/src/device/keyboard_xt.c index 7e419b39d..5190de839 100644 --- a/src/device/keyboard_xt.c +++ b/src/device/keyboard_xt.c @@ -69,6 +69,7 @@ enum { KBD_TYPE_ZENITH, KBD_TYPE_PRAVETZ, KBD_TYPE_HYUNDAI, + KBD_TYPE_FE2010, KBD_TYPE_XTCLONE }; @@ -80,6 +81,7 @@ typedef struct xtkbd_t { uint8_t pa; uint8_t pb; uint8_t pd; + uint8_t cfg; uint8_t clock; uint8_t key_waiting; uint8_t type; @@ -832,12 +834,26 @@ kbd_write(uint16_t port, uint8_t val, void *priv) kbd_log("XTkbd: Cassette motor is %s\n", !(val & 0x08) ? "ON" : "OFF"); #endif break; -#ifdef ENABLE_KEYBOARD_XT_LOG + case 0x62: /* Switch Register (aka Port C) */ +#ifdef ENABLE_KEYBOARD_XT_LOG if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ)) kbd_log("XTkbd: Cassette IN is %i\n", !!(val & 0x10)); - break; #endif + if (kbd->type == KBD_TYPE_FE2010) { + kbd_log("XTkbd: Switch register in is %02X\n", val); + if (!(kbd->cfg & 0x08)) + kbd->pd = (kbd->pd & 0x30) | (val & 0xcf); + } + break; + + case 0x63: + if (kbd->type == KBD_TYPE_FE2010) { + kbd_log("XTkbd: Configuration register in is %02X\n", val); + if (!(kbd->cfg & 0x08)) + kbd->cfg = val; + } + break; case 0xc0 ... 0xcf: /* Pravetz Flags */ kbd_log("XTkbd: Port %02X out: %02X\n", port, val); @@ -912,7 +928,12 @@ kbd_read(uint16_t port, void *priv) break; case 0x62: /* Switch Register (aka Port C) */ - if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || + if (kbd->type == KBD_TYPE_FE2010) { + if (kbd->pb & 0x04) /* PB2 */ + ret = (kbd->pd & 0x0d) | (hasfpu ? 0x02 : 0x00); + else + ret = kbd->pd >> 4; + } else if ((kbd->type == KBD_TYPE_PC81) || (kbd->type == KBD_TYPE_PC82) || (kbd->type == KBD_TYPE_PRAVETZ)) { if (kbd->pb & 0x04) /* PB2 */ switch (mem_size + isa_mem_size) { @@ -1037,7 +1058,7 @@ kbd_init(const device_t *info) (kbd->type <= KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_COMPAQ) || (kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_OLIVETTI) || (kbd->type == KBD_TYPE_HYUNDAI) || - (kbd->type == KBD_TYPE_VTECH)) { + (kbd->type == KBD_TYPE_VTECH) || (kbd->type == KBD_TYPE_FE2010)) { /* DIP switch readout: bit set = OFF, clear = ON. */ if (kbd->type == KBD_TYPE_OLIVETTI) /* Olivetti M19 @@ -1057,7 +1078,7 @@ kbd_init(const device_t *info) /* Switches 3, 4 - memory size. */ if ((kbd->type == KBD_TYPE_XT86) || (kbd->type == KBD_TYPE_XTCLONE) || (kbd->type == KBD_TYPE_HYUNDAI) || (kbd->type == KBD_TYPE_COMPAQ) || - (kbd->type == KBD_TYPE_TOSHIBA)) { + (kbd->type == KBD_TYPE_TOSHIBA) || (kbd->type == KBD_TYPE_FE2010)) { switch (mem_size) { case 256: kbd->pd |= 0x00; @@ -1356,7 +1377,7 @@ const device_t keyboard_xt_zenith_device = { const device_t keyboard_xt_hyundai_device = { .name = "Hyundai XT Keyboard", - .internal_name = "keyboard_x_hyundai", + .internal_name = "keyboard_xt_hyundai", .flags = 0, .local = KBD_TYPE_HYUNDAI, .init = kbd_init, @@ -1368,6 +1389,20 @@ const device_t keyboard_xt_hyundai_device = { .config = NULL }; +const device_t keyboard_xt_fe2010_device = { + .name = "Faraday FE2010 XT Keyboard", + .internal_name = "keyboard_xt_fe2010", + .flags = 0, + .local = KBD_TYPE_FE2010, + .init = kbd_init, + .close = kbd_close, + .reset = kbd_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t keyboard_xtclone_device = { .name = "XT (Clone) Keyboard", .internal_name = "keyboard_xtclone", diff --git a/src/device/novell_cardkey.c b/src/device/novell_cardkey.c index 8820addde..08334e751 100644 --- a/src/device/novell_cardkey.c +++ b/src/device/novell_cardkey.c @@ -109,7 +109,7 @@ static const device_config_t keycard_config[] = { }; const device_t novell_keycard_device = { - .name = "Novell Netware 2.x Key Card", + .name = "Novell NetWare 2.x Key Card", .internal_name = "mssystems", .flags = DEVICE_ISA, .local = 0, diff --git a/src/floppy/fdc_monster.c b/src/floppy/fdc_monster.c index b91d4db66..04536520f 100644 --- a/src/floppy/fdc_monster.c +++ b/src/floppy/fdc_monster.c @@ -183,7 +183,7 @@ static const device_config_t monster_fdc_config[] = { #if 0 { .name = "bios_size", - .description = "BIOS Size:", + .description = "BIOS size", .type = CONFIG_HEX20, .default_string = NULL, .default_int = 32, diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index 8bf303961..e572d670b 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -177,6 +177,8 @@ extern char usr_path[1024]; /* path (dir) of user data */ extern char cfg_path[1024]; /* full path of config file */ extern int open_dir_usr_path; /* default file open dialog directory of usr_path */ extern char uuid[MAX_UUID_LEN]; /* UUID or machine identifier */ +extern char vmm_path[1024]; /* VM Manager path to scan (temporary) */ +extern int vmm_enabled; #ifndef USE_NEW_DYNAREC extern FILE *stdlog; /* file to log output to */ #endif diff --git a/src/include/86box/chipset.h b/src/include/86box/chipset.h index 1b5684414..7ee8182ea 100644 --- a/src/include/86box/chipset.h +++ b/src/include/86box/chipset.h @@ -18,6 +18,7 @@ #define EMU_CHIPSET_H /* ACC */ +extern const device_t acc2036_device; extern const device_t acc2168_device; /* ALi */ @@ -123,7 +124,9 @@ extern const device_t opti381_device; extern const device_t opti391_device; extern const device_t opti481_device; extern const device_t opti493_device; -extern const device_t opti495_device; +extern const device_t opti495slc_device; +extern const device_t opti495sx_device; +extern const device_t opti498_device; extern const device_t opti499_device; extern const device_t opti601_device; extern const device_t opti602_device; diff --git a/src/include/86box/flash.h b/src/include/86box/flash.h index 6f0e1ff15..bd9b7e505 100644 --- a/src/include/86box/flash.h +++ b/src/include/86box/flash.h @@ -20,6 +20,7 @@ #ifndef EMU_FLASH_H #define EMU_FLASH_H +extern const device_t amd_am28f010_flash_device; extern const device_t catalyst_flash_device; extern const device_t intel_flash_bxt_ami_device; diff --git a/src/include/86box/keyboard.h b/src/include/86box/keyboard.h index b9bac0821..62938fae4 100644 --- a/src/include/86box/keyboard.h +++ b/src/include/86box/keyboard.h @@ -228,6 +228,7 @@ extern const device_t keyboard_xt_lxt3_device; extern const device_t keyboard_xt_olivetti_device; extern const device_t keyboard_xt_zenith_device; extern const device_t keyboard_xt_hyundai_device; +extern const device_t keyboard_xt_fe2010_device; extern const device_t keyboard_xtclone_device; extern const device_t keyboard_at_device; extern const device_t keyboard_at_ami_device; diff --git a/src/include/86box/m_pcjr.h b/src/include/86box/m_pcjr.h new file mode 100644 index 000000000..c6cb33588 --- /dev/null +++ b/src/include/86box/m_pcjr.h @@ -0,0 +1,74 @@ +/* + * 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. + * + * Header files for the PCjr keyboard and video subsystems. + * + * + * + * Authors: Connor Hyde, + * + * Copyright 2025 starfrost + */ + +#pragma once + +#define PCJR_RGB 0 +#define PCJR_COMPOSITE 1 +#define PCJR_RGB_NO_BROWN 4 +#define PCJR_RGB_IBM_5153 5 + +typedef struct pcjr_s +{ + /* Video Controller stuff. */ + mem_mapping_t mapping; + uint8_t crtc[32]; + int crtcreg; + int array_index; + uint8_t array[32]; + int array_ff; + int memctrl; + uint8_t status; + int addr_mode; + uint8_t *vram; + uint8_t *b8000; + int linepos; + int displine; + int scanline; + int vc; + int dispon; + int cursorvisible; // Is the cursor visible on the current scanline? + int cursoron; + int blink; + int vsynctime; + int fullchange; + int vadj; + uint16_t memaddr; + uint16_t memaddr_backup; + uint64_t dispontime; + uint64_t dispofftime; + pc_timer_t timer; + int firstline; + int lastline; + int composite; + int apply_hd; + + /* Keyboard Controller stuff. */ + int latched; + int data; + int serial_data[44]; + int serial_pos; + uint8_t pa; + uint8_t pb; + pc_timer_t send_delay_timer; + +} pcjr_t; + +void pcjr_recalc_timings(pcjr_t *pcjr); + +// Note: This is a temporary solution until the pcjr video is made its own gfx card +void pcjr_vid_init(pcjr_t *pcjr); \ No newline at end of file diff --git a/src/include/86box/m_tandy.h b/src/include/86box/m_tandy.h new file mode 100644 index 000000000..2d0100c1a --- /dev/null +++ b/src/include/86box/m_tandy.h @@ -0,0 +1,95 @@ +/* + * 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. + * + * Header files for the Tandy keyboard and video subsystems. + * + * + * + * Authors: Connor Hyde, + * + * Copyright 2025 starfrost + */ + +typedef struct t1kvid_t { + mem_mapping_t mapping; + mem_mapping_t vram_mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[256]; + int memctrl; + uint8_t mode; + uint8_t col; + uint8_t status; + + uint8_t *vram; + uint8_t *b8000; + uint32_t b8000_mask; + uint32_t b8000_limit; + uint8_t planar_ctrl; + uint8_t lp_strobe; + + int linepos; + int displine; + int scanline; + int vc; + int dispon; + int cursorvisible; + int cursoron; + int blink; + int fullchange; + int vsynctime; + int vadj; + uint16_t memaddr; + uint16_t memaddr_backup; + + uint64_t dispontime; + uint64_t dispofftime; + pc_timer_t timer; + int firstline; + int lastline; + + int composite; +} t1kvid_t; + +typedef struct t1keep_t { + char *path; + + int state; + int count; + int addr; + int clk; + uint16_t data; + uint16_t store[64]; +} t1keep_t; + +typedef struct tandy_t { + mem_mapping_t ram_mapping; + mem_mapping_t rom_mapping; /* SL2 */ + + uint8_t *rom; /* SL2 */ + uint8_t ram_bank; + uint8_t rom_bank; /* SL2 */ + int rom_offset; /* SL2 */ + + uint32_t base; + uint32_t mask; + int is_hx; + int is_sl2; + + t1kvid_t *vid; +} tandy_t; + +void tandy_vid_init(tandy_t* dev); +uint8_t tandy_vid_in(uint16_t addr, void* priv); +void tandy_vid_out(uint16_t addr, uint8_t val, void *priv); + +void tandy_vid_close(void* priv); +void tandy_recalc_address_sl(tandy_t* dev); //this function is needed by both m_ and vid_tandy.c diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 7aec5db4f..90b596ae8 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -197,6 +197,7 @@ enum { MACHINE_CHIPSET_GC100A, MACHINE_CHIPSET_GC103, MACHINE_CHIPSET_HT18, + MACHINE_CHIPSET_ACC_2036, MACHINE_CHIPSET_ACC_2168, MACHINE_CHIPSET_ALI_M1217, MACHINE_CHIPSET_ALI_M6117, @@ -240,7 +241,9 @@ enum { MACHINE_CHIPSET_OPTI_391, MACHINE_CHIPSET_OPTI_481, MACHINE_CHIPSET_OPTI_493, - MACHINE_CHIPSET_OPTI_495, + MACHINE_CHIPSET_OPTI_495SLC, + MACHINE_CHIPSET_OPTI_495SX, + MACHINE_CHIPSET_OPTI_498, MACHINE_CHIPSET_OPTI_499, MACHINE_CHIPSET_OPTI_895_802G, MACHINE_CHIPSET_OPTI_547_597, @@ -456,6 +459,7 @@ extern int machine_at_px286_init(const machine_t *); extern int machine_at_quadt286_init(const machine_t *); extern int machine_at_mr286_init(const machine_t *); +extern int machine_at_pbl300sx_init(const machine_t *); extern int machine_at_neat_init(const machine_t *); extern int machine_at_neat_ami_init(const machine_t *); extern int machine_at_ataripc4_init(const machine_t *); @@ -475,6 +479,7 @@ extern int machine_at_kmxc02_init(const machine_t *); extern int machine_at_deskmaster286_init(const machine_t *); extern int machine_at_dells200_init(const machine_t *); +extern int machine_at_at122_init(const machine_t *); extern int machine_at_tuliptc7_init(const machine_t *); extern int machine_at_pc8_init(const machine_t *); @@ -544,6 +549,7 @@ extern int machine_at_winbios1429_init(const machine_t *); extern int machine_at_opti495_init(const machine_t *); extern int machine_at_opti495_ami_init(const machine_t *); extern int machine_at_opti495_mr_init(const machine_t *); +extern int machine_at_c747_init(const machine_t *); extern int machine_at_exp4349_init(const machine_t *); extern int machine_at_vect486vl_init(const machine_t *); @@ -564,6 +570,7 @@ extern int machine_at_dtk461_init(const machine_t *); extern int machine_at_sis401_init(const machine_t *); extern int machine_at_isa486_init(const machine_t *); extern int machine_at_av4_init(const machine_t *); +extern int machine_at_advantage40xxd_init(const machine_t *); extern int machine_at_valuepoint433_init(const machine_t *); extern int machine_at_vli486sv2g_init(const machine_t *); @@ -973,6 +980,7 @@ extern int machine_xt_kaypropc_init(const machine_t *); extern int machine_xt_sansx16_init(const machine_t *); extern int machine_xt_bw230_init(const machine_t *); extern int machine_xt_pb8810_init(const machine_t *); +extern int machine_xt_tuliptc8_init(const machine_t *); extern int machine_xt_v20xt_init(const machine_t *); diff --git a/src/include/86box/sio.h b/src/include/86box/sio.h index 358cd8c9a..0b07d7a13 100644 --- a/src/include/86box/sio.h +++ b/src/include/86box/sio.h @@ -125,6 +125,10 @@ extern const device_t sio_detect_device; #endif /* USE_SIO_DETECT */ /* UMC */ +extern const device_t um82c862f_device; +extern const device_t um82c862f_ide_device; +extern const device_t um82c863f_device; +extern const device_t um82c863f_ide_device; extern const device_t um8663af_device; extern const device_t um8663af_ide_device; extern const device_t um8663af_sec_device; diff --git a/src/include/86box/vid_8514a.h b/src/include/86box/vid_8514a.h index 92960f912..9d19d916c 100644 --- a/src/include/86box/vid_8514a.h +++ b/src/include/86box/vid_8514a.h @@ -80,7 +80,7 @@ typedef struct ibm8514_t { uint32_t vram_mask; uint32_t pallook[512]; uint32_t bios_addr; - uint32_t ma_latch; + uint32_t memaddr_latch; PALETTE vgapal; uint8_t hwcursor_oddeven; @@ -220,8 +220,8 @@ typedef struct ibm8514_t { int lastline_draw; int displine; int fullchange; - uint32_t ma; - uint32_t maback; + uint32_t memaddr; + uint32_t memaddr_backup; uint8_t *vram; uint8_t *changedvram; @@ -236,7 +236,7 @@ typedef struct ibm8514_t { int hdisp; int hdisp2; int hdisped; - int sc; + int scanline; int vsyncstart; int vsyncwidth; int vtotal; diff --git a/src/include/86box/vid_ati_mach8.h b/src/include/86box/vid_ati_mach8.h index d5e80d0c8..e999c7087 100644 --- a/src/include/86box/vid_ati_mach8.h +++ b/src/include/86box/vid_ati_mach8.h @@ -137,6 +137,7 @@ typedef struct mach_t { int16_t dx_end; int16_t dy; int16_t dy_end; + int16_t dx_first_row_start; int16_t dx_start; int16_t dy_start; int16_t cy; diff --git a/src/include/86box/vid_cga.h b/src/include/86box/vid_cga.h index 2a36eeade..04616431e 100644 --- a/src/include/86box/vid_cga.h +++ b/src/include/86box/vid_cga.h @@ -11,7 +11,8 @@ * * * Authors: Sarah Walker, - * Miran Grca, + * Miran Grca, , + * Connor Hyde / starfrost, * * Copyright 2008-2018 Sarah Walker. * Copyright 2016-2018 Miran Grca. @@ -56,6 +57,7 @@ typedef enum cga_crtc_registers_e CGA_CRTC_LIGHT_PEN_ADDR_LOW = 0x11, // Light pen address low 8 bits (not currently supported) } cga_crtc_registers; +// Registers for the CGA typedef enum cga_registers_e { CGA_REGISTER_CRTC_INDEX = 0x3D4, @@ -85,16 +87,16 @@ typedef struct cga_t { int fontbase; int linepos; int displine; - int sc; + int scanline; int vc; int cgadispon; - int con; + int cursorvisible; // Determines if the cursor is visible FOR THE CURRENT SCANLINE. int cursoron; int cgablink; int vsynctime; int vadj; - uint16_t ma; - uint16_t maback; + uint16_t memaddr; + uint16_t memaddr_backup; int oddeven; uint64_t dispontime; diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index c4c0ea2d7..beef6f98d 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -39,7 +39,7 @@ typedef struct ega_t { uint8_t lb; uint8_t lc; uint8_t ld; - uint8_t stat; + uint8_t status; uint8_t colourcompare; uint8_t colournocare; uint8_t scrblank; @@ -68,12 +68,12 @@ typedef struct ega_t { int chain4; int chain2_read; int chain2_write; - int con; + int cursorvisible; int oddeven_page; int oddeven_chain; int vc; int real_vc; - int sc; + int scanline; int dispon; int hdisp_on; int cursoron; @@ -115,14 +115,14 @@ typedef struct ega_t { int chipset; int mono_display; - int mdacols[256][2][2]; + int mda_attr_to_color_table[256][2][2]; uint32_t charseta; uint32_t charsetb; - uint32_t ma_latch; - uint32_t ma; - uint32_t maback; - uint32_t ca; + uint32_t memaddr_latch; + uint32_t memaddr; + uint32_t memaddr_backup; + uint32_t cursoraddr; uint32_t vram_limit; uint32_t overscan_color; uint32_t cca; @@ -189,11 +189,11 @@ extern void ega_set_type(void *priv, uint32_t local); extern int firstline_draw; extern int lastline_draw; extern int displine; -extern int sc; +extern int scanline; -extern uint32_t ma; -extern uint32_t ca; -extern int con; +extern uint32_t memaddr; +extern uint32_t cursoraddr; +extern int cursorvisible; extern int cursoron; extern int cgablink; diff --git a/src/include/86box/vid_ega_render_remap.h b/src/include/86box/vid_ega_render_remap.h index b01bb2b0e..1b0f7676c 100644 --- a/src/include/86box/vid_ega_render_remap.h +++ b/src/include/86box/vid_ega_render_remap.h @@ -33,9 +33,9 @@ } \ \ if (nr & VAR_ROW0_MA13) \ - out_addr = (out_addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); \ + out_addr = (out_addr & ~0x8000) | ((ega->scanline & 1) ? 0x8000 : 0); \ if (nr & VAR_ROW1_MA14) \ - out_addr = (out_addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); \ + out_addr = (out_addr & ~0x10000) | ((ega->scanline & 2) ? 0x10000 : 0); \ \ return out_addr; \ } diff --git a/src/include/86box/vid_hercules.h b/src/include/86box/vid_hercules.h index a468dce55..1d62bee67 100644 --- a/src/include/86box/vid_hercules.h +++ b/src/include/86box/vid_hercules.h @@ -13,10 +13,12 @@ * Authors: Sarah Walker, * Miran Grca, * Jasmine Iwanek, - * + * Connor Hyde / starfrost, + */ #ifndef VIDEO_MDA_H #define VIDEO_MDA_H +// Defines +#define MDA_CRTC_NUM_REGISTERS 32 + +// Enums & structures + +typedef enum mda_registers_e +{ + MDA_REGISTER_START = 0x3B0, + + MDA_REGISTER_CRTC_INDEX = 0x3B4, + MDA_REGISTER_CRTC_DATA = 0x3B5, + MDA_REGISTER_MODE_CONTROL = 0x3B8, + MDA_REGISTER_CRT_STATUS = 0x3BA, + MDA_REGISTER_PARALLEL_DATA = 0x3BC, + MDA_REGISTER_PRINTER_STATUS = 0x3BD, + MDA_REGISTER_PRINTER_CONTROL = 0x3BE, + + MDA_REGISTER_END = 0x3BF, +} mda_registers; + +// Motorola MC6845 CRTC registers (without light pen for some reason) +typedef enum mda_crtc_registers_e +{ + MDA_CRTC_HTOTAL = 0x0, // Horizontal total (total number of characters incl. hsync) + MDA_CRTC_HDISP = 0x1, // Horizontal display + MDA_CRTC_HSYNC_POS = 0x2, // Horizontal position of horizontal ysnc + MDA_CRTC_HSYNC_WIDTH = 0x3, // Width of horizontal sync + MDA_CRTC_VTOTAL = 0x4, // Vertical total (total number of scanlines incl. vsync) + MDA_CRTC_VTOTAL_ADJUST = 0x5, // Vertical total adjust value + MDA_CRTC_VDISP = 0x6, // Vertical display (total number of displayed scanline) + MDA_CRTC_VSYNC = 0x7, // Vertical sync scanline number + MDA_CRTC_INTERLACE = 0x8, // Interlacing mode + MDA_CRTC_MAX_SCANLINE_ADDR = 0x9, // Maximum scanline address + MDA_CRTC_CURSOR_START = 0xA, // Cursor start scanline + MDA_CRTC_CURSOR_END = 0xB, // Cursor end scanline + MDA_CRTC_START_ADDR_HIGH = 0xC, // Screen start address high 8 bits + MDA_CRTC_START_ADDR_LOW = 0xD, // Screen start address low 8 bits + MDA_CRTC_CURSOR_ADDR_HIGH = 0xE, // Cursor address high 8 bits + MDA_CRTC_CURSOR_ADDR_LOW = 0xF, // Cursor address low 8 bits +} mda_crtc_registers; + +typedef enum mda_mode_flags_e +{ + MDA_MODE_HIGHRES = 1 << 0, // MUST be enabled for sane operation + MDA_MODE_BW = 1 << 1, // UNUSED in most cases. Not present on Hercules + MDA_MODE_VIDEO_ENABLE = 1 << 3, + MDA_MODE_BLINK = 1 << 5, +} mda_mode_flags; + +typedef enum mda_colors_e +{ + MDA_COLOR_BLACK = 0, + MDA_COLOR_BLUE = 1, + MDA_COLOR_GREEN = 2, + MDA_COLOR_CYAN = 3, + MDA_COLOR_RED = 4, + MDA_COLOR_MAGENTA = 5, + MDA_COLOR_BROWN = 6, + MDA_COLOR_WHITE = 7, + MDA_COLOR_GREY = 8, + MDA_COLOR_BRIGHT_BLUE = 9, + MDA_COLOR_BRIGHT_GREEN = 10, + MDA_COLOR_BRIGHT_CYAN = 11, + MDA_COLOR_BRIGHT_RED = 12, + MDA_COLOR_BRIGHT_MAGENTA = 13, + MDA_COLOR_BRIGHT_YELLOW = 14, + MDA_COLOR_BRIGHT_WHITE = 15, +} mda_colors; + typedef struct mda_t { mem_mapping_t mapping; - uint8_t crtc[32]; - int crtcreg; + uint8_t crtc[MDA_CRTC_NUM_REGISTERS]; + int32_t crtcreg; - uint8_t ctrl; - uint8_t stat; + uint8_t mode; + uint8_t status; - uint64_t dispontime; - uint64_t dispofftime; - pc_timer_t timer; + uint64_t dispontime; + uint64_t dispofftime; + pc_timer_t timer; - int firstline; - int lastline; + int32_t firstline; + int32_t lastline; - int fontbase; - int linepos; - int displine; - int vc; - int sc; - uint16_t ma; - uint16_t maback; - int con; - int cursoron; - int dispon; - int blink; - int vsynctime; - int vadj; - int monitor_index; - int prev_monitor_index; + int32_t fontbase; + int32_t linepos; + int32_t displine; + int32_t vc; + int32_t scanline; + uint16_t memaddr; + uint16_t memaddr_backup; + int32_t cursorvisible; + int32_t cursoron; + int32_t dispon; + int32_t blink; + int32_t vsynctime; + int32_t vadj; + int32_t monitor_index; + int32_t prev_monitor_index; + int32_t monitor_type; // Used for MDA Colour support (REV0 u64) uint8_t *vram; } mda_t; diff --git a/src/include/86box/vid_pgc.h b/src/include/86box/vid_pgc.h index 43226a0f5..dd6a45b98 100644 --- a/src/include/86box/vid_pgc.h +++ b/src/include/86box/vid_pgc.h @@ -115,13 +115,13 @@ typedef struct pgc { int displine; int vc; int cgadispon; - int con; + int cursorvisible; int cursoron; int cgablink; int vsynctime; int vadj; - uint16_t ma; - uint16_t maback; + uint16_t memaddr; + uint16_t memaddr_backup; int oddeven; uint64_t dispontime; diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 6b817f0ee..ad9170ad3 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -100,12 +100,12 @@ typedef struct svga_t { int dispon; int hdisp_on; int vc; - int sc; + int scanline; int linepos; int vslines; int linecountff; int oddeven; - int con; + int cursorvisible; int cursoron; int blink; int scrollcache; @@ -152,15 +152,15 @@ typedef struct svga_t { uint32_t charseta; uint32_t charsetb; uint32_t adv_flags; - uint32_t ma_latch; + uint32_t memaddr_latch; uint32_t ca_adj; - uint32_t ma; - uint32_t maback; + uint32_t memaddr; + uint32_t memaddr_backup; uint32_t write_bank; uint32_t read_bank; uint32_t extra_banks[2]; uint32_t banked_mask; - uint32_t ca; + uint32_t cursoraddr; uint32_t overscan_color; uint32_t *map8; uint32_t pallook[512]; diff --git a/src/include/86box/vid_svga_render.h b/src/include/86box/vid_svga_render.h index babac7592..097bb4509 100644 --- a/src/include/86box/vid_svga_render.h +++ b/src/include/86box/vid_svga_render.h @@ -23,11 +23,11 @@ extern int firstline_draw; extern int lastline_draw; extern int displine; -extern int sc; +extern int scanline; -extern uint32_t ma; -extern uint32_t ca; -extern int con; +extern uint32_t memaddr; +extern uint32_t cursoraddr; +extern int cursorvisible; extern int cursoron; extern int cgablink; diff --git a/src/include/86box/vid_svga_render_remap.h b/src/include/86box/vid_svga_render_remap.h index ff9151c3c..d6c9fa5a6 100644 --- a/src/include/86box/vid_svga_render_remap.h +++ b/src/include/86box/vid_svga_render_remap.h @@ -47,9 +47,9 @@ } \ \ if (nr & VAR_ROW0_MA13) \ - out_addr = (out_addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); \ + out_addr = (out_addr & ~0x8000) | ((svga->scanline & 1) ? 0x8000 : 0); \ if (nr & VAR_ROW1_MA14) \ - out_addr = (out_addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); \ + out_addr = (out_addr & ~0x10000) | ((svga->scanline & 2) ? 0x10000 : 0); \ \ return out_addr; \ } diff --git a/src/include/86box/vid_xga.h b/src/include/86box/vid_xga.h index b2001dba9..e72c7af40 100644 --- a/src/include/86box/vid_xga.h +++ b/src/include/86box/vid_xga.h @@ -127,7 +127,7 @@ typedef struct xga_t { int dispon; int h_disp_on; int vc; - int sc; + int scanline; int linepos; int oddeven; int firstline; @@ -160,12 +160,12 @@ typedef struct xga_t { uint32_t hwc_color0; uint32_t hwc_color1; uint32_t disp_start_addr; - uint32_t ma_latch; + uint32_t memaddr_latch; uint32_t vram_size; uint32_t vram_mask; uint32_t rom_addr; - uint32_t ma; - uint32_t maback; + uint32_t memaddr; + uint32_t memaddr_backup; uint32_t read_bank; uint32_t write_bank; uint32_t px_map_base; diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 8cd672a63..e00cca6ac 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -75,6 +75,7 @@ enum { #define FONT_IBM_MDA_437_NORDIC_PATH "roms/video/mda/4733197.bin" #define FONT_KAM_PATH "roms/video/mda/kam.bin" #define FONT_KAMCL16_PATH "roms/video/mda/kamcl16.bin" +#define FONT_TULIP_DGA_PATH "roms/video/mda/tulip-dga-bios.bin" typedef struct video_timings_t { int type; @@ -187,6 +188,10 @@ extern bitmap_t *buffer32; #define efscrnsz_y (monitors[monitor_index_global].mon_efscrnsz_y) #define unscaled_size_x (monitors[monitor_index_global].mon_unscaled_size_x) #define unscaled_size_y (monitors[monitor_index_global].mon_unscaled_size_y) + +#define CGAPAL_CGA_START 16 // Where the 16-color cga text/composite starts + + extern PALETTE cgapal; extern PALETTE cgapal_mono[6]; #if 0 @@ -359,6 +364,7 @@ extern const device_t gd5420_isa_device; extern const device_t gd5420_onboard_device; extern const device_t gd5422_isa_device; extern const device_t gd5424_vlb_device; +extern const device_t gd5424_onboard_device; extern const device_t gd5426_isa_device; extern const device_t gd5426_diamond_speedstar_pro_a1_isa_device; extern const device_t gd5426_vlb_device; @@ -395,6 +401,7 @@ extern const device_t gd5480_pci_device; /* Compaq CGA */ extern const device_t compaq_cga_device; extern const device_t compaq_cga_2_device; +extern const device_t compaq_plasma_device; /* Olivetti OGC */ extern const device_t ogc_device; @@ -467,6 +474,7 @@ extern const device_t if386jega_device; /* Oak OTI-0x7 */ extern const device_t oti037c_device; +extern const device_t oti037_pbl300sx_device; extern const device_t oti067_device; extern const device_t oti067_acer386_device; extern const device_t oti067_ama932j_device; @@ -613,6 +621,11 @@ extern const device_t nv3t_device_agp; /* Wyse 700 */ extern const device_t wy700_device; +/* Tandy */ +extern const device_t tandy_1000_video_device; +extern const device_t tandy_1000hx_video_device; +extern const device_t tandy_1000sl_video_device; + #endif #endif /*EMU_VIDEO_H*/ diff --git a/src/machine/CMakeLists.txt b/src/machine/CMakeLists.txt index 8cd54edec..f91eeb17d 100644 --- a/src/machine/CMakeLists.txt +++ b/src/machine/CMakeLists.txt @@ -23,7 +23,6 @@ add_library(mch OBJECT m_xt_laserxt.c m_xt_philips.c m_xt_t1000.c - m_xt_t1000_vid.c m_xt_xi8088.c m_xt_zenith.c m_pcjr.c @@ -37,7 +36,6 @@ add_library(mch OBJECT m_at_commodore.c m_at_grid.c m_at_t3100e.c - m_at_t3100e_vid.c m_ps1.c m_ps1_hdc.c m_ps2_isa.c diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 57e8367ff..d42807b4d 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -105,7 +105,7 @@ typedef struct amsvid_t { int cga_enabled; /* 1640 */ uint8_t cgacol; uint8_t cgamode; - uint8_t stat; + uint8_t status; uint8_t plane_write; /* 1512/200 */ uint8_t plane_read; /* 1512/200 */ uint8_t border; /* 1512/200 */ @@ -113,17 +113,17 @@ typedef struct amsvid_t { int fontbase; /* 1512/200 */ int linepos; int displine; - int sc; + int scanline; int vc; int cgadispon; - int con; + int cursorvisible; int cursoron; int cgablink; int vsynctime; int fullchange; int vadj; - uint16_t ma; - uint16_t maback; + uint16_t memaddr; + uint16_t memaddr_backup; int dispon; int blink; uint64_t dispontime; /* 1512/1640 */ @@ -290,7 +290,7 @@ vid_in_1512(uint16_t addr, void *priv) break; case 0x03da: - ret = vid->stat; + ret = vid->status; break; default: @@ -339,7 +339,7 @@ static void vid_poll_1512(void *priv) { amsvid_t *vid = (amsvid_t *) priv; - uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; + uint16_t cursoraddr = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; int drawcursor; int x; int c; @@ -353,13 +353,13 @@ vid_poll_1512(void *priv) uint16_t dat4; int cols[4]; int col; - int oldsc; + int scanline_old; if (!vid->linepos) { timer_advance_u64(&vid->timer, vid->dispofftime); - vid->stat |= 1; + vid->status |= 1; vid->linepos = 1; - oldsc = vid->sc; + scanline_old = vid->scanline; if (vid->dispon) { if (vid->displine < vid->firstline) { vid->firstline = vid->displine; @@ -369,26 +369,26 @@ vid_poll_1512(void *priv) for (c = 0; c < 8; c++) { if ((vid->cgamode & 0x12) == 0x12) { buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->border & 15) + 16; - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = 0; } else { buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = 0; } } else { buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->cgacol & 15) + 16; - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = (vid->cgacol & 15) + 16; } else { buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = (vid->cgacol & 15) + 16; } } } - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { for (x = 0; x < 80; x++) { - chr = vid->vram[(vid->ma << 1) & 0x3fff]; - attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->cgamode & 0x20) { + chr = vid->vram[(vid->memaddr<< 1) & 0x3fff]; + attr = vid->vram[((vid->memaddr<< 1) + 1) & 0x3fff]; + drawcursor = ((vid->memaddr== cursoraddr) && vid->cursorvisible && vid->cursoron); + if (vid->cgamode & CGA_MODE_FLAG_BLINK) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) @@ -399,21 +399,23 @@ vid_poll_1512(void *priv) } if (drawcursor) { for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[vid->fontbase + chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } } else { for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[vid->fontbase + chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } - vid->ma++; + vid->memaddr++; } - } else if (!(vid->cgamode & 2)) { + } else if (!(vid->cgamode & CGA_MODE_FLAG_GRAPHICS)) { for (x = 0; x < 40; x++) { - chr = vid->vram[(vid->ma << 1) & 0x3fff]; - attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->cgamode & 0x20) { + chr = vid->vram[(vid->memaddr<< 1) & 0x3fff]; + attr = vid->vram[((vid->memaddr<< 1) + 1) & 0x3fff]; + drawcursor = ((vid->memaddr == cursoraddr) + && vid->cursorvisible && vid->cursoron); + + if (vid->cgamode & CGA_MODE_FLAG_BLINK) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; if ((vid->blink & 16) && (attr & 0x80)) @@ -422,21 +424,21 @@ vid_poll_1512(void *priv) cols[1] = (attr & 15) + 16; cols[0] = (attr >> 4) + 16; } - vid->ma++; + vid->memaddr++; if (drawcursor) { for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[vid->fontbase + chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } } else { for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[vid->fontbase + chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[vid->fontbase + chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } } - } else if (!(vid->cgamode & 16)) { + } else if (!(vid->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { cols[0] = (vid->cgacol & 15) | 16; col = (vid->cgacol & 16) ? 24 : 16; - if (vid->cgamode & 4) { + if (vid->cgamode & CGA_MODE_FLAG_BW) { cols[1] = col | 3; cols[2] = col | 4; cols[3] = col | 7; @@ -450,8 +452,8 @@ vid_poll_1512(void *priv) cols[3] = col | 6; } for (x = 0; x < 40; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; + dat = (vid->vram[((vid->memaddr<< 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000)] << 8) | vid->vram[((vid->memaddr<< 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000) + 1]; + vid->memaddr++; for (c = 0; c < 8; c++) { buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; @@ -459,13 +461,13 @@ vid_poll_1512(void *priv) } } else { for (x = 0; x < 40; x++) { - ca = ((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000); - dat = (vid->vram[ca] << 8) | vid->vram[ca + 1]; - dat2 = (vid->vram[ca + 0x4000] << 8) | vid->vram[ca + 0x4001]; - dat3 = (vid->vram[ca + 0x8000] << 8) | vid->vram[ca + 0x8001]; - dat4 = (vid->vram[ca + 0xc000] << 8) | vid->vram[ca + 0xc001]; + cursoraddr = ((vid->memaddr<< 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000); + dat = (vid->vram[cursoraddr] << 8) | vid->vram[cursoraddr + 1]; + dat2 = (vid->vram[cursoraddr + 0x4000] << 8) | vid->vram[cursoraddr + 0x4001]; + dat3 = (vid->vram[cursoraddr + 0x8000] << 8) | vid->vram[cursoraddr + 0x8001]; + dat4 = (vid->vram[cursoraddr + 0xc000] << 8) | vid->vram[cursoraddr + 0xc001]; - vid->ma++; + vid->memaddr++; for (c = 0; c < 16; c++) { buffer32->line[vid->displine << 1][(x << 4) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] = (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (vid->cgacol & 15)) + 16; dat <<= 1; @@ -477,7 +479,7 @@ vid_poll_1512(void *priv) } } else { cols[0] = ((vid->cgamode & 0x12) == 0x12) ? 0 : (vid->cgacol & 15) + 16; - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, cols[0]); hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, cols[0]); } else { @@ -486,7 +488,7 @@ vid_poll_1512(void *priv) } } - if (vid->cgamode & 1) + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) x = (vid->crtc[1] << 3) + 16; else x = (vid->crtc[1] << 4) + 16; @@ -494,9 +496,9 @@ vid_poll_1512(void *priv) video_process_8(x, vid->displine << 1); video_process_8(x, (vid->displine << 1) + 1); - vid->sc = oldsc; + vid->scanline = scanline_old; if (vid->vsynctime) - vid->stat |= 8; + vid->status |= 8; vid->displine++; if (vid->displine >= 360) vid->displine = 0; @@ -505,29 +507,29 @@ vid_poll_1512(void *priv) if ((vid->lastline - vid->firstline) == 199) vid->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ if (vid->dispon) - vid->stat &= ~1; + vid->status &= ~1; vid->linepos = 0; if (vid->vsynctime) { vid->vsynctime--; if (!vid->vsynctime) - vid->stat &= ~8; + vid->status &= ~8; } - if (vid->sc == (vid->crtc[11] & 31)) { - vid->con = 0; + if (vid->scanline == (vid->crtc[11] & 31)) { + vid->cursorvisible = 0; } if (vid->vadj) { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; + vid->scanline++; + vid->scanline &= 31; + vid->memaddr= vid->memaddr_backup; vid->vadj--; if (!vid->vadj) { vid->dispon = 1; - vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; - vid->sc = 0; + vid->memaddr= vid->memaddr_backup = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + vid->scanline = 0; } - } else if (vid->sc == vid->crtc[9]) { - vid->maback = vid->ma; - vid->sc = 0; + } else if (vid->scanline == vid->crtc[9]) { + vid->memaddr_backup = vid->memaddr; + vid->scanline = 0; vid->vc++; vid->vc &= 127; @@ -545,7 +547,7 @@ vid_poll_1512(void *priv) vid->displine = 0; vid->vsynctime = 46; - if (vid->cgamode & 1) + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) x = (vid->crtc[1] << 3) + 16; else x = (vid->crtc[1] << 4) + 16; @@ -582,15 +584,15 @@ vid_poll_1512(void *priv) video_res_x = xsize; video_res_y = ysize; - if (vid->cgamode & 1) { + if (vid->cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; video_res_y /= vid->crtc[9] + 1; video_bpp = 0; - } else if (!(vid->cgamode & 2)) { + } else if (!(vid->cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; video_res_y /= vid->crtc[9] + 1; video_bpp = 0; - } else if (!(vid->cgamode & 16)) { + } else if (!(vid->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { video_res_x /= 2; video_bpp = 2; } else { @@ -602,12 +604,12 @@ vid_poll_1512(void *priv) vid->blink++; } } else { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; + vid->scanline++; + vid->scanline &= 31; + vid->memaddr= vid->memaddr_backup; } - if (vid->sc == (vid->crtc[10] & 31)) - vid->con = 1; + if (vid->scanline == (vid->crtc[10] & 31)) + vid->cursorvisible = 1; } } @@ -1044,7 +1046,7 @@ vid_in_200(uint16_t addr, void *priv) switch (addr) { case 0x03b8: - return (mda->ctrl); + return (mda->mode); case 0x03d8: return (cga->cgamode); @@ -1106,9 +1108,9 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) } return; case 0x3b8: - old = mda->ctrl; - mda->ctrl = val; - if ((mda->ctrl ^ old) & 3) + old = mda->mode; + mda->mode = val; + if ((mda->mode ^ old) & 3) mda_recalctimings(mda); vid->crtc_index &= 0x1F; vid->crtc_index |= 0x80; @@ -1210,11 +1212,11 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) static void lcd_draw_char_80(amsvid_t *vid, uint32_t *buffer, uint8_t chr, - uint8_t attr, int drawcursor, int blink, int sc, + uint8_t attr, int drawcursor, int blink, int scanline, int mode160, uint8_t control) { int c; - uint8_t bits = fontdat[chr + vid->cga.fontbase][sc]; + uint8_t bits = fontdat[chr + vid->cga.fontbase][scanline]; uint8_t bright = 0; uint16_t mask; @@ -1245,10 +1247,10 @@ lcd_draw_char_80(amsvid_t *vid, uint32_t *buffer, uint8_t chr, static void lcd_draw_char_40(amsvid_t *vid, uint32_t *buffer, uint8_t chr, - uint8_t attr, int drawcursor, int blink, int sc, + uint8_t attr, int drawcursor, int blink, int scanline, uint8_t control) { - uint8_t bits = fontdat[chr + vid->cga.fontbase][sc]; + uint8_t bits = fontdat[chr + vid->cga.fontbase][scanline]; uint8_t mask = 0x80; if (attr & 8) /* bright */ @@ -1269,91 +1271,91 @@ static void lcdm_poll(amsvid_t *vid) { mda_t *mda = &vid->mda; - uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; + uint16_t cursoraddr = (mda->crtc[MDA_CRTC_CURSOR_ADDR_LOW] | (mda->crtc[MDA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; int drawcursor; int x; int oldvc; uint8_t chr; uint8_t attr; - int oldsc; + int scanline_old; int blink; if (!mda->linepos) { timer_advance_u64(&vid->timer, mda->dispofftime); - mda->stat |= 1; + mda->status |= 1; mda->linepos = 1; - oldsc = mda->sc; - if ((mda->crtc[8] & 3) == 3) - mda->sc = (mda->sc << 1) & 7; + scanline_old = mda->scanline; + if ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3) + mda->scanline = (mda->scanline << 1) & 7; if (mda->dispon) { if (mda->displine < mda->firstline) mda->firstline = mda->displine; mda->lastline = mda->displine; - for (x = 0; x < mda->crtc[1]; x++) { - chr = mda->vram[(mda->ma << 1) & 0xfff]; - attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; - drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); - blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + for (x = 0; x < mda->crtc[MDA_CRTC_HDISP]; x++) { + chr = mda->vram[(mda->memaddr<< 1) & 0xfff]; + attr = mda->vram[((mda->memaddr<< 1) + 1) & 0xfff]; + drawcursor = ((mda->memaddr== cursoraddr) && mda->cursorvisible && mda->cursoron); + blink = ((mda->blink & 16) && (mda->mode & MDA_MODE_BLINK) && (attr & 0x80) && !drawcursor); - lcd_draw_char_80(vid, &(buffer32->line[mda->displine])[x * 8], chr, attr, drawcursor, blink, mda->sc, 0, mda->ctrl); - mda->ma++; + lcd_draw_char_80(vid, &(buffer32->line[mda->displine])[x * 8], chr, attr, drawcursor, blink, mda->scanline, 0, mda->mode); + mda->memaddr++; } } - mda->sc = oldsc; - if (mda->vc == mda->crtc[7] && !mda->sc) - mda->stat |= 8; + mda->scanline = scanline_old; + if (mda->vc == mda->crtc[MDA_CRTC_VSYNC] && !mda->scanline) + mda->status |= 8; mda->displine++; if (mda->displine >= 500) mda->displine = 0; } else { timer_advance_u64(&vid->timer, mda->dispontime); if (mda->dispon) - mda->stat &= ~1; + mda->status &= ~1; mda->linepos = 0; if (mda->vsynctime) { mda->vsynctime--; if (!mda->vsynctime) - mda->stat &= ~8; + mda->status &= ~8; } - if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) { - mda->con = 0; + if (mda->scanline == (mda->crtc[MDA_CRTC_CURSOR_END] & 31) || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 && mda->scanline == ((mda->crtc[MDA_CRTC_CURSOR_END] & 31) >> 1))) { + mda->cursorvisible = 0; } if (mda->vadj) { - mda->sc++; - mda->sc &= 31; - mda->ma = mda->maback; + mda->scanline++; + mda->scanline &= 31; + mda->memaddr= mda->memaddr_backup; mda->vadj--; if (!mda->vadj) { mda->dispon = 1; - mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; - mda->sc = 0; + mda->memaddr= mda->memaddr_backup = (mda->crtc[MDA_CRTC_START_ADDR_LOW] | (mda->crtc[MDA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + mda->scanline = 0; } - } else if (mda->sc == mda->crtc[9] || ((mda->crtc[8] & 3) == 3 && mda->sc == (mda->crtc[9] >> 1))) { - mda->maback = mda->ma; - mda->sc = 0; + } else if (mda->scanline == mda->crtc[MDA_CRTC_MAX_SCANLINE_ADDR] || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 && mda->scanline == (mda->crtc[MDA_CRTC_MAX_SCANLINE_ADDR] >> 1))) { + mda->memaddr_backup = mda->memaddr; + mda->scanline = 0; oldvc = mda->vc; mda->vc++; mda->vc &= 127; - if (mda->vc == mda->crtc[6]) + if (mda->vc == mda->crtc[MDA_CRTC_VDISP]) mda->dispon = 0; - if (oldvc == mda->crtc[4]) { + if (oldvc == mda->crtc[MDA_CRTC_VTOTAL]) { mda->vc = 0; - mda->vadj = mda->crtc[5]; + mda->vadj = mda->crtc[MDA_CRTC_VTOTAL_ADJUST]; if (!mda->vadj) mda->dispon = 1; if (!mda->vadj) - mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; - if ((mda->crtc[10] & 0x60) == 0x20) + mda->memaddr= mda->memaddr_backup = (mda->crtc[MDA_CRTC_START_ADDR_LOW] | (mda->crtc[MDA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + if ((mda->crtc[MDA_CRTC_CURSOR_START] & 0x60) == 0x20) mda->cursoron = 0; else mda->cursoron = mda->blink & 16; } - if (mda->vc == mda->crtc[7]) { + if (mda->vc == mda->crtc[MDA_CRTC_VSYNC]) { mda->dispon = 0; mda->displine = 0; mda->vsynctime = 16; - if (mda->crtc[7]) { - x = mda->crtc[1] * 8; + if (mda->crtc[MDA_CRTC_VSYNC]) { + x = mda->crtc[MDA_CRTC_HDISP] * 8; mda->lastline++; if ((x != xsize) || ((mda->lastline - mda->firstline) != ysize) || video_force_resize_get()) { xsize = x; @@ -1369,8 +1371,8 @@ lcdm_poll(amsvid_t *vid) } video_blit_memtoscreen(0, mda->firstline, xsize, ysize); frames++; - video_res_x = mda->crtc[1]; - video_res_y = mda->crtc[6]; + video_res_x = mda->crtc[MDA_CRTC_HDISP]; + video_res_y = mda->crtc[MDA_CRTC_VDISP]; video_bpp = 0; } mda->firstline = 1000; @@ -1378,12 +1380,12 @@ lcdm_poll(amsvid_t *vid) mda->blink++; } } else { - mda->sc++; - mda->sc &= 31; - mda->ma = mda->maback; + mda->scanline++; + mda->scanline &= 31; + mda->memaddr= mda->memaddr_backup; } - if (mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1))) - mda->con = 1; + if (mda->scanline == (mda->crtc[MDA_CRTC_CURSOR_START] & 31) || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 && mda->scanline == ((mda->crtc[MDA_CRTC_CURSOR_START] & 31) >> 1))) + mda->cursorvisible = 1; } } @@ -1399,19 +1401,19 @@ lcdc_poll(amsvid_t *vid) uint8_t chr; uint8_t attr; uint16_t dat; - int oldsc; - uint16_t ca; + int scanline_old; + uint16_t cursoraddr; int blink; - ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + cursoraddr = (cga->crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (cga->crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; if (!cga->linepos) { timer_advance_u64(&vid->timer, cga->dispofftime); cga->cgastat |= 1; cga->linepos = 1; - oldsc = cga->sc; - if ((cga->crtc[8] & 3) == 3) - cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; + scanline_old = cga->scanline; + if ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3) + cga->scanline = ((cga->scanline << 1) + cga->oddeven) & 7; if (cga->cgadispon) { if (cga->displine < cga->firstline) { cga->firstline = cga->displine; @@ -1419,30 +1421,30 @@ lcdc_poll(amsvid_t *vid) } cga->lastline = cga->displine; - if (cga->cgamode & 1) { - for (x = 0; x < cga->crtc[1]; x++) { + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { + for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { chr = cga->charbuffer[x << 1]; attr = cga->charbuffer[(x << 1) + 1]; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); - blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); - lcd_draw_char_80(vid, &(buffer32->line[cga->displine << 1])[x * 8], chr, attr, drawcursor, blink, cga->sc, cga->cgamode & 0x40, cga->cgamode); - lcd_draw_char_80(vid, &(buffer32->line[(cga->displine << 1) + 1])[x * 8], chr, attr, drawcursor, blink, cga->sc, cga->cgamode & 0x40, cga->cgamode); - cga->ma++; + drawcursor = ((cga->memaddr == cursoraddr) && cga->cursorvisible && cga->cursoron); + blink = ((cga->cgablink & 16) && (cga->cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); + lcd_draw_char_80(vid, &(buffer32->line[cga->displine << 1])[x * 8], chr, attr, drawcursor, blink, cga->scanline, cga->cgamode & 0x40, cga->cgamode); + lcd_draw_char_80(vid, &(buffer32->line[(cga->displine << 1) + 1])[x * 8], chr, attr, drawcursor, blink, cga->scanline, cga->cgamode & 0x40, cga->cgamode); + cga->memaddr++; } - } else if (!(cga->cgamode & 2)) { - for (x = 0; x < cga->crtc[1]; x++) { - chr = cga->vram[(cga->ma << 1) & 0x3fff]; - attr = cga->vram[((cga->ma << 1) + 1) & 0x3fff]; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); - blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); - lcd_draw_char_40(vid, &(buffer32->line[cga->displine << 1])[x * 16], chr, attr, drawcursor, blink, cga->sc, cga->cgamode); - lcd_draw_char_40(vid, &(buffer32->line[(cga->displine << 1) + 1])[x * 16], chr, attr, drawcursor, blink, cga->sc, cga->cgamode); - cga->ma++; + } else if (!(cga->cgamode & CGA_MODE_FLAG_GRAPHICS)) { + for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { + chr = cga->vram[(cga->memaddr << 1) & 0x3fff]; + attr = cga->vram[((cga->memaddr << 1) + 1) & 0x3fff]; + drawcursor = ((cga->memaddr == cursoraddr) && cga->cursorvisible && cga->cursoron); + blink = ((cga->cgablink & 16) && (cga->cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); + lcd_draw_char_40(vid, &(buffer32->line[cga->displine << 1])[x * 16], chr, attr, drawcursor, blink, cga->scanline, cga->cgamode); + lcd_draw_char_40(vid, &(buffer32->line[(cga->displine << 1) + 1])[x * 16], chr, attr, drawcursor, blink, cga->scanline, cga->cgamode); + cga->memaddr++; } } else { /* Graphics mode */ - for (x = 0; x < cga->crtc[1]; x++) { - dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; - cga->ma++; + for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { + dat = (cga->vram[((cga->memaddr << 1) & 0x1fff) + ((cga->scanline & 1) * 0x2000)] << 8) | cga->vram[((cga->memaddr << 1) & 0x1fff) + ((cga->scanline & 1) * 0x2000) + 1]; + cga->memaddr++; for (uint8_t c = 0; c < 16; c++) { buffer32->line[cga->displine << 1][(x << 4) + c] = buffer32->line[(cga->displine << 1) + 1][(x << 4) + c] = (dat & 0x8000) ? blue : green; dat <<= 1; @@ -1450,22 +1452,22 @@ lcdc_poll(amsvid_t *vid) } } } else { - if (cga->cgamode & 1) { - hline(buffer32, 0, (cga->displine << 1), (cga->crtc[1] << 3), green); - hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[1] << 3), green); + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { + hline(buffer32, 0, (cga->displine << 1), (cga->crtc[CGA_CRTC_HDISP] << 3), green); + hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[CGA_CRTC_HDISP] << 3), green); } else { - hline(buffer32, 0, (cga->displine << 1), (cga->crtc[1] << 4), green); - hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[1] << 4), green); + hline(buffer32, 0, (cga->displine << 1), (cga->crtc[CGA_CRTC_HDISP] << 4), green); + hline(buffer32, 0, (cga->displine << 1) + 1, (cga->crtc[CGA_CRTC_HDISP] << 4), green); } } - if (cga->cgamode & 1) - x = (cga->crtc[1] << 3); + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (cga->crtc[CGA_CRTC_HDISP] << 3); else - x = (cga->crtc[1] << 4); + x = (cga->crtc[CGA_CRTC_HDISP] << 4); - cga->sc = oldsc; - if (cga->vc == cga->crtc[7] && !cga->sc) + cga->scanline = scanline_old; + if (cga->vc == cga->crtc[CGA_CRTC_VSYNC] && !cga->scanline) cga->cgastat |= 8; cga->displine++; if (cga->displine >= 360) @@ -1478,53 +1480,53 @@ lcdc_poll(amsvid_t *vid) if (!cga->vsynctime) cga->cgastat &= ~8; } - if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) { - cga->con = 0; + if (cga->scanline == (cga->crtc[CGA_CRTC_CURSOR_END] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->scanline == ((cga->crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + cga->cursorvisible = 0; } - if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) - cga->maback = cga->ma; + if ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->scanline == (cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) + cga->memaddr_backup = cga->memaddr; if (cga->vadj) { - cga->sc++; - cga->sc &= 31; - cga->ma = cga->maback; + cga->scanline++; + cga->scanline &= 31; + cga->memaddr = cga->memaddr_backup; cga->vadj--; if (!cga->vadj) { cga->cgadispon = 1; - cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; - cga->sc = 0; + cga->memaddr = cga->memaddr_backup = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + cga->scanline = 0; } - } else if (cga->sc == cga->crtc[9]) { - cga->maback = cga->ma; - cga->sc = 0; + } else if (cga->scanline == cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR]) { + cga->memaddr_backup = cga->memaddr; + cga->scanline = 0; oldvc = cga->vc; cga->vc++; cga->vc &= 127; - if (cga->vc == cga->crtc[6]) + if (cga->vc == cga->crtc[CGA_CRTC_VDISP]) cga->cgadispon = 0; - if (oldvc == cga->crtc[4]) { + if (oldvc == cga->crtc[CGA_CRTC_VTOTAL]) { cga->vc = 0; - cga->vadj = cga->crtc[5]; + cga->vadj = cga->crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!cga->vadj) cga->cgadispon = 1; if (!cga->vadj) - cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; - if ((cga->crtc[10] & 0x60) == 0x20) + cga->memaddr = cga->memaddr_backup = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + if ((cga->crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) cga->cursoron = 0; else cga->cursoron = cga->cgablink & 8; } - if (cga->vc == cga->crtc[7]) { + if (cga->vc == cga->crtc[CGA_CRTC_VSYNC]) { cga->cgadispon = 0; cga->displine = 0; cga->vsynctime = 16; - if (cga->crtc[7]) { - if (cga->cgamode & 1) - x = (cga->crtc[1] << 3); + if (cga->crtc[CGA_CRTC_VSYNC]) { + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (cga->crtc[CGA_CRTC_HDISP] << 3); else - x = (cga->crtc[1] << 4); + x = (cga->crtc[CGA_CRTC_HDISP] << 4); cga->lastline++; xs_temp = x; @@ -1536,7 +1538,7 @@ lcdc_poll(amsvid_t *vid) if (ys_temp < 32) ys_temp = 400; - if ((cga->cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + if ((cga->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { xsize = xs_temp; ysize = ys_temp; set_screen_size(xsize, ysize); @@ -1553,15 +1555,15 @@ lcdc_poll(amsvid_t *vid) video_res_x = xsize; video_res_y = ysize; - if (cga->cgamode & 1) { + if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; - video_res_y /= cga->crtc[9] + 1; + video_res_y /= cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; video_bpp = 0; - } else if (!(cga->cgamode & 2)) { + } else if (!(cga->cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; - video_res_y /= cga->crtc[9] + 1; + video_res_y /= cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; video_bpp = 0; - } else if (!(cga->cgamode & 16)) { + } else if (!(cga->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { video_res_x /= 2; video_bpp = 2; } else @@ -1573,17 +1575,17 @@ lcdc_poll(amsvid_t *vid) cga->oddeven ^= 1; } } else { - cga->sc++; - cga->sc &= 31; - cga->ma = cga->maback; + cga->scanline++; + cga->scanline &= 31; + cga->memaddr = cga->memaddr_backup; } if (cga->cgadispon) cga->cgastat &= ~1; - if (cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1))) - cga->con = 1; - if (cga->cgadispon && (cga->cgamode & 1)) { - for (x = 0; x < (cga->crtc[1] << 1); x++) - cga->charbuffer[x] = cga->vram[((cga->ma << 1) + x) & 0x3fff]; + if (cga->scanline == (cga->crtc[CGA_CRTC_CURSOR_START] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->scanline == ((cga->crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + cga->cursorvisible = 1; + if (cga->cgadispon && (cga->cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (cga->crtc[CGA_CRTC_HDISP] << 1); x++) + cga->charbuffer[x] = cga->vram[((cga->memaddr << 1) + x) & 0x3fff]; } } } diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 29298510c..eb5394ba4 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -169,6 +169,72 @@ machine_at_quadt386sx_init(const machine_t *model) return ret; } +static const device_config_t pbl300sx_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "pbl300sx", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .bios = { + { .name = "1991", .internal_name = "pbl300sx_1991", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pbl300sx/V1.10_1113_910723.bin", "" } }, + { .name = "1992", .internal_name = "pbl300sx", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/pbl300sx/pb_l300sx_1992.bin", "" } }, + { .files_no = 0 } + }, + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t pbl300sx_device = { + .name = "Packard Bell Legend 300SX", + .internal_name = "pbl300sx_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = pbl300sx_config +}; + +int +machine_at_pbl300sx_init(const machine_t *model) +{ + int ret = 0; + const char* fn; + + /* No ROMs available */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000e0000, 131072, 0); + device_context_restore(); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&acc2036_device); + + device_add(&keyboard_ps2_phoenix_device); + device_add(&um82c862f_ide_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + return ret; +} + int machine_at_neat_init(const machine_t *model) { @@ -292,6 +358,22 @@ machine_at_dells200_init(const machine_t *model) return ret; } +int +machine_at_at122_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/at122/FINAL.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_ctat_common_init(model); + + return ret; +} + int machine_at_tuliptc7_init(const machine_t *model) { @@ -1128,7 +1210,7 @@ machine_at_3302_init(const machine_t *model) device_add(&fdc_at_device); if (gfxcard[0] == VID_INTERNAL) - device_add(¶dise_pvga1a_ncr3302_device); + device_add(machine_get_vid_device(machine)); device_add(&keyboard_at_ncr_device); diff --git a/src/machine/m_at_386dx_486.c b/src/machine/m_at_386dx_486.c index 86a1aa087..0c0582c3c 100644 --- a/src/machine/m_at_386dx_486.c +++ b/src/machine/m_at_386dx_486.c @@ -682,7 +682,7 @@ machine_at_opti495_init(const machine_t *model) machine_at_common_init(model); - device_add(&opti495_device); + device_add(&opti495slc_device); device_add(&keyboard_at_device); @@ -697,7 +697,7 @@ machine_at_opti495_ami_common_init(const machine_t *model) { machine_at_common_init(model); - device_add(&opti495_device); + device_add(&opti495sx_device); device_add(&keyboard_at_ami_device); @@ -737,6 +737,32 @@ machine_at_opti495_mr_init(const machine_t *model) return ret; } +int +machine_at_c747_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/c747/486-C747 Tandon.BIN", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + + /* The EFAR chipset is a rebrand of the OPTi 495SX. */ + device_add(&opti495sx_device); + + /* + No idea what KBC it actually has but this produces the + desired behavior: command A9 does absolutely nothing. + */ + device_add(&keyboard_at_siemens_device); + device_add(&um82c862f_ide_device); + + return ret; +} + int machine_at_exp4349_init(const machine_t *model) { @@ -822,6 +848,7 @@ machine_at_403tg_d_mr_init(const machine_t *model) return ret; } + static const device_config_t pb450_config[] = { // clang-format off { @@ -974,7 +1001,8 @@ machine_at_mvi486_init(const machine_t *model) machine_at_common_init(model); - device_add(&opti495_device); + device_add(&opti498_device); + device_add(&keyboard_at_device); device_add(&pc87311_ide_device); @@ -1009,6 +1037,31 @@ machine_at_ami471_init(const machine_t *model) return ret; } +int +machine_at_advantage40xxd_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/advantage40xxd/AST101.09A", + 0x000e0000, 131072, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_init(model); + device_add(&sis_85c471_device); + + if (gfxcard[0] == VID_INTERNAL) + device_add(machine_get_vid_device(machine)); + + device_add(&keyboard_ps2_phoenix_device); + device_add(&um82c863f_ide_device); + + device_add(&intel_flash_bxt_device); + + return ret; +} + int machine_at_vli486sv2g_init(const machine_t *model) { @@ -2447,7 +2500,7 @@ machine_at_actionpc2600_init(const machine_t *model) device_add(&keyboard_ps2_tg_ami_device); if (gfxcard[0] == VID_INTERNAL) - device_add(&tgui9440_onboard_pci_device); + device_add(machine_get_vid_device(machine)); return ret; } @@ -2479,7 +2532,7 @@ machine_at_actiontower8400_init(const machine_t *model) device_add(&intel_flash_bxt_device); // The ActionPC 2600 has this so I'm gonna assume this does too. device_add(&keyboard_ps2_ami_pci_device); if (gfxcard[0] == VID_INTERNAL) - device_add(&gd5430_onboard_pci_device); + device_add(machine_get_vid_device(machine)); return ret; } diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 1f5ecdb58..2fbfed0ff 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -44,9 +44,6 @@ #include <86box/vid_cga_comp.h> #include <86box/plat_unused.h> - -static video_timings_t timing_compaq_plasma = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; - enum { COMPAQ_PORTABLEII = 0, COMPAQ_PORTABLEIII, @@ -55,752 +52,11 @@ enum { COMPAQ_DESKPRO386_05_1988 }; -#define CGA_RGB 0 -#define CGA_COMPOSITE 1 - -/*Very rough estimate*/ -#define VID_CLOCK (double) (651 * 416 * 60) - -/* Mapping of attributes to colours */ -static uint32_t amber; -static uint32_t black; -static uint32_t blinkcols[256][2]; -static uint32_t normcols[256][2]; - -/* Video options set by the motherboard; they will be picked up by the card - * on the next poll. - * - * Bit 3: Disable built-in video (for add-on card) - * Bit 2: Thin font - * Bits 0,1: Font set (not currently implemented) - */ -static int8_t cpq_st_display_internal = -1; - -static uint8_t mdaattr[256][2][2]; - -static void -compaq_plasma_display_set(uint8_t internal) -{ - cpq_st_display_internal = internal; -} - -typedef struct compaq_plasma_t { - cga_t cga; - mem_mapping_t font_ram_mapping; - uint8_t *font_ram; - uint8_t port_13c6; - uint8_t port_23c6; - uint8_t port_27c6; - uint8_t internal_monitor; -} compaq_plasma_t; - static int compaq_machine_type = 0; /* Compaq Deskpro 386 remaps RAM from 0xA0000-0xFFFFF to 0xFA0000-0xFFFFFF */ static mem_mapping_t ram_mapping; -static void compaq_plasma_recalcattrs(compaq_plasma_t *self); - -static void -compaq_plasma_recalctimings(compaq_plasma_t *self) -{ - double _dispontime; - double _dispofftime; - double disptime; - - if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { - cga_recalctimings(&self->cga); - return; - } - - disptime = 651; - _dispontime = 640; - _dispofftime = disptime - _dispontime; - self->cga.dispontime = (uint64_t) (_dispontime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); - self->cga.dispofftime = (uint64_t) (_dispofftime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); -} - -static void -compaq_plasma_waitstates(UNUSED(void *priv)) -{ - int ws_array[16] = { 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8 }; - int ws; - - ws = ws_array[cycles & 0xf]; - sub_cycles(ws); -} - -static void -compaq_plasma_write(uint32_t addr, uint8_t val, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - if (self->port_23c6 & 0x08) - self->font_ram[addr & 0x1fff] = val; - else - self->cga.vram[addr & 0x7fff] = val; - - compaq_plasma_waitstates(&self->cga); -} -static uint8_t -compaq_plasma_read(uint32_t addr, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - uint8_t ret; - - compaq_plasma_waitstates(&self->cga); - - if (self->port_23c6 & 0x08) - ret = (self->font_ram[addr & 0x1fff]); - else - ret = (self->cga.vram[addr & 0x7fff]); - - return ret; -} - -static void -compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - switch (addr) { - /* Emulated CRTC, register select */ - case 0x3d0: - case 0x3d2: - case 0x3d4: - case 0x3d6: - cga_out(addr, val, &self->cga); - break; - - /* Emulated CRTC, value */ - case 0x3d1: - case 0x3d3: - case 0x3d5: - case 0x3d7: - cga_out(addr, val, &self->cga); - compaq_plasma_recalctimings(self); - break; - case 0x3d8: - case 0x3d9: - cga_out(addr, val, &self->cga); - break; - - case 0x13c6: - self->port_13c6 = val; - compaq_plasma_display_set((self->port_13c6 & 0x08) ? 1 : 0); - /* - For bits 2-0, John gives 0 = CGA, 1 = EGA, 3 = MDA; - Another source (Ralf Brown?) gives 4 = CGA, 5 = EGA, 7 = MDA; - This leads me to believe bit 2 is not relevant to the mode. - */ - if ((val & 0x03) == 0x03) - mem_mapping_set_addr(&self->cga.mapping, 0xb0000, 0x08000); - else - mem_mapping_set_addr(&self->cga.mapping, 0xb8000, 0x08000); - break; - - case 0x23c6: - self->port_23c6 = val; - compaq_plasma_recalcattrs(self); - break; - - case 0x27c6: - self->port_27c6 = val; - break; - - default: - break; - } -} - -static uint8_t -compaq_plasma_in(uint16_t addr, void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - uint8_t ret = 0xff; - - switch (addr) { - case 0x3d4: - case 0x3da: - case 0x3db: - case 0x3dc: - ret = cga_in(addr, &self->cga); - break; - - case 0x3d1: - case 0x3d3: - case 0x3d5: - case 0x3d7: - ret = cga_in(addr, &self->cga); - break; - - case 0x3d8: - ret = self->cga.cgamode; - break; - - case 0x13c6: - ret = self->port_13c6; -#if 0 - if ((self->cga.cgamode & 0x28) == 0x00) - ret |= 0x04; -#endif - break; - - case 0x17c6: - ret = 0xe6; - break; - - case 0x1bc6: - ret = 0x40; - break; - - case 0x23c6: - ret = self->port_23c6; - break; - - case 0x27c6: - ret = self->port_27c6 & 0x3f; - break; - - default: - break; - } - - return ret; -} - -static void -compaq_plasma_poll(void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - uint8_t chr; - uint8_t attr; - uint8_t sc; - uint16_t ma = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x7fff; - uint16_t ca = (self->cga.crtc[15] | (self->cga.crtc[14] << 8)) & 0x7fff; - uint16_t addr; - int drawcursor; - int cursorline; - int blink = 0; - int underline = 0; - int c; - int x; - uint32_t ink = 0; - uint32_t fg = (self->cga.cgacol & 0x0f) ? amber : black; - uint32_t bg = black; - uint32_t cols[2]; - uint8_t dat; - uint8_t pattern; - uint32_t ink0 = 0; - uint32_t ink1 = 0; - - /* Switch between internal plasma and external CRT display. */ - if ((cpq_st_display_internal != -1) && (cpq_st_display_internal != self->internal_monitor)) { - self->internal_monitor = cpq_st_display_internal; - compaq_plasma_recalctimings(self); - } - - /* graphic mode and not mode 40h */ - if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { - /* standard cga mode */ - cga_poll(&self->cga); - return; - } else { - /* mode 40h or text mode */ - if (!self->cga.linepos) { - timer_advance_u64(&self->cga.timer, self->cga.dispofftime); - self->cga.cgastat |= 1; - self->cga.linepos = 1; - if (self->cga.cgadispon) { - if (self->cga.displine == 0) - video_wait_for_buffer(); - - /* 80-col */ - if (self->cga.cgamode & 0x01) { - sc = self->cga.displine & 0x0f; - addr = ((ma & ~1) + (self->cga.displine >> 4) * 80) << 1; - ma += (self->cga.displine >> 4) * 80; - - if ((self->cga.crtc[0x0a] & 0x60) == 0x20) - cursorline = 0; - else - cursorline = (((self->cga.crtc[0x0a] & 0x0f) << 1) <= sc) && (((self->cga.crtc[0x0b] & 0x0f) << 1) >= sc); - - /* for each text column */ - for (x = 0; x < 80; x++) { - /* video output enabled */ - if (self->cga.cgamode & 0x08) { - /* character */ - chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; - /* text attributes */ - attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; - } else { - chr = 0x00; - attr = 0x00; - } - uint8_t hi_bit = attr & 0x08; - /* check if cursor has to be drawn */ - drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); - /* check if character underline mode should be set */ - underline = ((attr & 0x07) == 0x01); - underline = underline || (((self->port_23c6 >> 5) == 2) && hi_bit); - if (underline) { - /* set forecolor to white */ - attr = attr | 0x7; - } - blink = 0; - /* set foreground */ - cols[1] = blinkcols[attr][1]; - /* blink active */ - if (self->cga.cgamode & 0x20) { - cols[0] = blinkcols[attr][0]; - /* attribute 7 active and not cursor */ - if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { - /* set blinking */ - cols[1] = cols[0]; - blink = 1; - } - } else { - /* Set intensity bit */ - cols[1] = normcols[attr][1]; - cols[0] = normcols[attr][0]; - } - - /* character address */ - uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; - if (((self->port_23c6 >> 5) == 3) && hi_bit) - chr_addr |= 0x1000; - - /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (sc == 7)) { - /* for each pixel in character width */ - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = mdaattr[attr][blink][1]; - } else if (drawcursor) { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); - } else { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; - } - - if (hi_bit) { - if ((self->port_23c6 >> 5) == 1) { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 3) + c] ^= (amber ^ black); - } else if ((self->port_23c6 >> 5) == 4) { - for (c = 0; c < 8; c++) { - uint32_t b = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 1) & 0x7f; - uint32_t g = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 9) & 0x7f; - uint32_t r = ((buffer32->line[self->cga.displine][(x << 3) + c]) >> 17) & 0x7f; - buffer32->line[self->cga.displine][(x << 3) + c] = b | (g << 8) || (r << 16); - } - } - } - ma++; - } - } - /* 40-col */ - else if (!(self->cga.cgamode & 0x02)) { - sc = self->cga.displine & 0x0f; - addr = ((ma & ~1) + (self->cga.displine >> 4) * 40) << 1; - ma += (self->cga.displine >> 4) * 40; - - if ((self->cga.crtc[0x0a] & 0x60) == 0x20) - cursorline = 0; - else - cursorline = (((self->cga.crtc[0x0a] & 0x0f) << 1) <= sc) && (((self->cga.crtc[0x0b] & 0x0f) << 1) >= sc); - - for (x = 0; x < 40; x++) { - /* video output enabled */ - if (self->cga.cgamode & 0x08) { - /* character */ - chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; - /* text attributes */ - attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; - } else { - chr = 0x00; - attr = 0x00; - } - uint8_t hi_bit = attr & 0x08; - /* check if cursor has to be drawn */ - drawcursor = ((ma == ca) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); - /* check if character underline mode should be set */ - underline = ((attr & 0x07) == 0x01); - underline = underline || (((self->port_23c6 >> 5) == 2) && hi_bit); - if (underline) { - /* set forecolor to white */ - attr = attr | 0x7; - } - blink = 0; - /* set foreground */ - cols[1] = blinkcols[attr][1]; - /* blink active */ - if (self->cga.cgamode & 0x20) { - cols[0] = blinkcols[attr][0]; - /* attribute 7 active and not cursor */ - if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { - /* set blinking */ - cols[1] = cols[0]; - blink = 1; - } - } else { - /* Set intensity bit */ - cols[1] = normcols[attr][1]; - cols[0] = normcols[attr][0]; - } - - /* character address */ - uint16_t chr_addr = ((chr * 16) + sc) & 0x0fff; - if (((self->port_23c6 >> 5) == 3) && hi_bit) - chr_addr |= 0x1000; - - /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (sc == 7)) { - /* for each pixel in character width */ - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = mdaattr[attr][blink][1]; - } else if (drawcursor) { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); - } else { - for (c = 0; c < 8; c++) - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; - } - - if (hi_bit) { - if ((self->port_23c6 >> 5) == 1) - for (c = 0; c < 8; c++) { - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] ^= (amber ^ black); - buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] ^= (amber ^ black); - } - else if ((self->port_23c6 >> 5) == 4) - for (c = 0; c < 8; c++) { - uint32_t b = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 1) & 0x7f; - uint32_t g = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 9) & 0x7f; - uint32_t r = ((buffer32->line[self->cga.displine][(x << 4) + (c << 1)]) >> 17) & 0x7f; - buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = b | (g << 8) || (r << 16); - } - } - ma++; - } - } else { - if (self->cga.cgamode & 0x10) { - /* 640x400 mode */ - if (self->port_23c6 & 0x01) /* 640*400 */ { - addr = ((self->cga.displine) & 1) * 0x2000 + ((self->cga.displine >> 1) & 1) * 0x4000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - } else { - addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - } - for (uint8_t x = 0; x < 80; x++) { - dat = self->cga.vram[addr & 0x7fff]; - addr++; - - for (uint8_t c = 0; c < 8; c++) { - ink = (dat & 0x80) ? fg : bg; - if (!(self->cga.cgamode & 0x08)) - ink = black; - buffer32->line[self->cga.displine][(x << 3) + c] = ink; - dat <<= 1; - } - } - } else { - addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((ma & ~1) << 1); - for (uint8_t x = 0; x < 80; x++) { - dat = self->cga.vram[addr & 0x7fff]; - addr++; - - for (uint8_t c = 0; c < 4; c++) { - pattern = (dat & 0xC0) >> 6; - if (!(self->cga.cgamode & 0x08)) - pattern = 0; - - switch (pattern & 3) { - case 0: - ink0 = ink1 = black; - break; - case 1: - if (self->cga.displine & 0x01) { - ink0 = black; - ink1 = black; - } else { - ink0 = amber; - ink1 = black; - } - break; - case 2: - if (self->cga.displine & 0x01) { - ink0 = black; - ink1 = amber; - } else { - ink0 = amber; - ink1 = black; - } - break; - case 3: - ink0 = ink1 = amber; - break; - - default: - break; - } - buffer32->line[self->cga.displine][(x << 3) + (c << 1)] = ink0; - buffer32->line[self->cga.displine][(x << 3) + (c << 1) + 1] = ink1; - dat <<= 2; - } - } - } - } - } - self->cga.displine++; - /* Hardcode a fixed refresh rate and VSYNC timing */ - if (self->cga.displine == 400) { /* Start of VSYNC */ - self->cga.cgastat |= 8; - self->cga.cgadispon = 0; - } - if (self->cga.displine == 416) { /* End of VSYNC */ - self->cga.displine = 0; - self->cga.cgastat &= ~8; - self->cga.cgadispon = 1; - } - } else { - timer_advance_u64(&self->cga.timer, self->cga.dispontime); - if (self->cga.cgadispon) - self->cga.cgastat &= ~1; - - self->cga.linepos = 0; - - if (self->cga.displine == 400) { - xsize = 640; - ysize = 400; - - if ((self->cga.cgamode & 0x08) || video_force_resize_get()) { - set_screen_size(xsize, ysize); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - /* Plasma specific */ - video_blit_memtoscreen(0, 0, xsize, ysize); - frames++; - - /* Fixed 640x400 resolution */ - video_res_x = 640; - video_res_y = 400; - - if (self->cga.cgamode & 0x02) { - if (self->cga.cgamode & 0x10) - video_bpp = 1; - else - video_bpp = 2; - } else - video_bpp = 0; - - self->cga.cgablink++; - } - } - } -} - -static void -compaq_plasma_mdaattr_rebuild(void) -{ - for (uint16_t c = 0; c < 256; c++) { - mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; - if (c & 8) - mdaattr[c][0][1] = 15 + 16; - else - mdaattr[c][0][1] = 7 + 16; - } - - mdaattr[0x70][0][1] = 16; - mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; - mdaattr[0xF0][0][1] = 16; - mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; - mdaattr[0x78][0][1] = 16 + 7; - mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; - mdaattr[0xF8][0][1] = 16 + 7; - mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; - mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; - mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; - mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; - mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; -} - -static void -compaq_plasma_recalcattrs(compaq_plasma_t *self) -{ - int n; - - /* val behaves as follows: - * Bit 0: Attributes 01-06, 08-0E are inverse video - * Bit 1: Attributes 01-06, 08-0E are bold - * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF - * are inverse video - * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF - * are bold */ - - /* Set up colours */ - amber = makecol(0xff, 0x7d, 0x00); - black = makecol(0x64, 0x19, 0x00); - - /* Initialize the attribute mapping. Start by defaulting everything - * to black on amber, and with bold set by bit 3 */ - for (n = 0; n < 256; n++) { - blinkcols[n][0] = normcols[n][0] = amber; - blinkcols[n][1] = normcols[n][1] = black; - } - - /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the - * passed value. Exclude x0 and x8, which are always black on - * amber. */ - for (n = 0x11; n <= 0xFF; n++) { - if ((n & 7) == 0) - continue; - if ((self->port_23c6 >> 5) == 1) { /* Inverse */ - blinkcols[n][0] = normcols[n][0] = amber; - blinkcols[n][1] = normcols[n][1] = black; - } else { /* Normal */ - blinkcols[n][0] = normcols[n][0] = black; - blinkcols[n][1] = normcols[n][1] = amber; - } - } - /* Set up the 01-0E range, controlled by bits 0 and 1 of the - * passed value. When blinking is enabled this also affects 81-8E. */ - for (n = 0x01; n <= 0x0E; n++) { - if (n == 7) - continue; - if ((self->port_23c6 >> 5) == 1) { - blinkcols[n][0] = normcols[n][0] = amber; - blinkcols[n][1] = normcols[n][1] = black; - blinkcols[n + 128][0] = amber; - blinkcols[n + 128][1] = black; - } else { - blinkcols[n][0] = normcols[n][0] = black; - blinkcols[n][1] = normcols[n][1] = amber; - blinkcols[n + 128][0] = black; - blinkcols[n + 128][1] = amber; - } - } - /* Colours 07 and 0F are always amber on black. If blinking is - * enabled so are 87 and 8F. */ - for (n = 0x07; n <= 0x0F; n += 8) { - blinkcols[n][0] = normcols[n][0] = black; - blinkcols[n][1] = normcols[n][1] = amber; - blinkcols[n + 128][0] = black; - blinkcols[n + 128][1] = amber; - } - /* When not blinking, colours 81-8F are always amber on black. */ - for (n = 0x81; n <= 0x8F; n++) { - normcols[n][0] = black; - normcols[n][1] = amber; - } - - /* Finally do the ones which are solid black. These differ between - * the normal and blinking mappings */ - for (n = 0; n <= 0xFF; n += 0x11) - normcols[n][0] = normcols[n][1] = black; - - /* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are black */ - for (n = 0; n <= 0x77; n += 0x11) { - blinkcols[n][0] = blinkcols[n][1] = black; - blinkcols[n + 128][0] = blinkcols[n + 128][1] = black; - } -} - -static void * -compaq_plasma_init(UNUSED(const device_t *info)) -{ - compaq_plasma_t *self = calloc(1, sizeof(compaq_plasma_t)); - - cga_init(&self->cga); - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_compaq_plasma); - - self->cga.composite = 0; - self->cga.revision = 0; - - self->cga.vram = malloc(0x8000); - self->internal_monitor = 1; - self->font_ram = malloc(0x2000); - - cga_comp_init(self->cga.revision); - timer_set_callback(&self->cga.timer, compaq_plasma_poll); - timer_set_p(&self->cga.timer, self); - - mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, - compaq_plasma_read, NULL, NULL, - compaq_plasma_write, NULL, NULL, - NULL, MEM_MAPPING_EXTERNAL, self); - for (int i = 1; i <= 2; i++) { - io_sethandler(0x03c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - io_sethandler(0x07c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - io_sethandler(0x0bc6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - } - io_sethandler(0x03d0, 0x0010, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); - - overscan_x = overscan_y = 16; - - self->cga.rgb_type = device_get_config_int("rgb_type"); - cga_palette = (self->cga.rgb_type << 1); - cgapal_rebuild(); - compaq_plasma_mdaattr_rebuild(); - - return self; -} - -static void -compaq_plasma_close(void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - free(self->cga.vram); - free(self->font_ram); - free(self); -} - -static void -compaq_plasma_speed_changed(void *priv) -{ - compaq_plasma_t *self = (compaq_plasma_t *) priv; - - compaq_plasma_recalctimings(self); -} - -const device_config_t compaq_plasma_config[] = { - // clang-format off - { - .name = "rgb_type", - .description = "RGB type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = 0, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "Color", .value = 0 }, - { .description = "Green Monochrome", .value = 1 }, - { .description = "Amber Monochrome", .value = 2 }, - { .description = "Gray Monochrome", .value = 3 }, - { .description = "" } - } - }, - { .name = "", .description = "", .type = CONFIG_END } - // clang-format on -}; - -const device_t compaq_plasma_device = { - .name = "Compaq Plasma", - .internal_name = "compaq_plasma", - .flags = 0, - .local = 0, - .init = compaq_plasma_init, - .close = compaq_plasma_close, - .reset = NULL, - .available = NULL, - .speed_changed = compaq_plasma_speed_changed, - .force_redraw = NULL, - .config = compaq_plasma_config -}; static uint8_t read_ram(uint32_t addr, UNUSED(void *priv)) diff --git a/src/machine/m_at_socket5.c b/src/machine/m_at_socket5.c index 3ed2bd2c7..b2d3c46f3 100644 --- a/src/machine/m_at_socket5.c +++ b/src/machine/m_at_socket5.c @@ -96,21 +96,21 @@ machine_at_d842_init(const machine_t *model) ret = bios_load_linear(fn, 0x000e0000, 131072, 0); device_context_restore(); - machine_at_common_init(model); + machine_at_common_init(model); device_add(&ide_pci_2ch_device); pci_init(PCI_CONFIG_TYPE_2 | PCI_NO_IRQ_STEERING); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); /* Onboard */ - pci_register_slot(0x03, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Onboard */ - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); /* Slot 01 */ - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); /* Slot 02 */ + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); /* Onboard */ + pci_register_slot(0x03, PCI_CARD_VIDEO, 4, 0, 0, 0); /* Onboard */ + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); /* Slot 01 */ + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); /* Slot 02 */ device_add(&keyboard_ps2_pci_device); device_add(&i430nx_device); device_add(&sio_zb_device); device_add(&fdc37c665_device); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); return ret; } @@ -127,18 +127,17 @@ static const device_config_t d842_config[] = { .spinner = { 0 }, /*W1*/ .bios = { { .name = "Version 1.03 Revision 1.03.842 (11/24/1994)", .internal_name = "d842", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842.bin", "" } }, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842.BIN", "" } }, { .name = "Version 4.04 Revision 1.05.842 (03/15/1996)", .internal_name = "d842_mar96", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842_mar96.bin", "" } }, { .name = "Version 4.04 Revision 1.06.842 (04/03/1998)", .internal_name = "d842_apr98", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842_apr98.bin", "" } }, - { .name = "Version 4.04 Revision 1.07.842 (06/02/1998)", .internal_name = "d842_jun98", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842_jun98.bin", "" } }, - { .name = "Version 1.03 Revision 1.09.842 (07/08/1996)", .internal_name = "d842_jul96", .bios_type = BIOS_NORMAL, + { .name = "Version 4.04 Revision 1.07.842 (06/02/1998)", .internal_name = "d842_jun98", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842_jun98.BIN", "" } }, + { .name = "Version 1.03 Revision 1.09.842 (07/08/1996)", .internal_name = "d842_jul96", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842_jul96.bin", "" } }, - { .name = "Version 1.03 Revision 1.10.842 (06/04/1998)", .internal_name = "d842_jun98_1", .bios_type = BIOS_NORMAL, - .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842_jun98_1.bin", "" } }, - + { .name = "Version 1.03 Revision 1.10.842 (06/04/1998)", .internal_name = "d842_jun98_1", .bios_type = BIOS_NORMAL, + .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d842/d842_jun98_1.bin", "" } }, }, }, { .name = "", .description = "", .type = CONFIG_END } @@ -155,7 +154,7 @@ const device_t d842_device = { .init = NULL, .close = NULL, .reset = NULL, - .available = NULL, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = &d842_config[0] diff --git a/src/machine/m_at_socket7_3v.c b/src/machine/m_at_socket7_3v.c index 7dd1f9bf0..7d29a6f3a 100644 --- a/src/machine/m_at_socket7_3v.c +++ b/src/machine/m_at_socket7_3v.c @@ -628,25 +628,24 @@ machine_at_d943_init(const machine_t *model) ret = bios_load_linear(fn, 0x000e0000, 131072, 0); device_context_restore(); - machine_at_common_init_ex(model, 2); - device_add(&amstrad_megapc_nvr_device); + machine_at_common_init_ex(model, 2); + device_add(&amstrad_megapc_nvr_device); pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 2, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_VIDEO, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 3, 2, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 1, 3, 2, 4); device_add(&i430hx_device); device_add(&piix3_device); device_add(&keyboard_ps2_pci_device); device_add(&fdc37c665_device); device_add(&intel_flash_bxt_device); - spd_register(SPD_TYPE_EDO, 0x7, 256); - - - if (gfxcard[0] == VID_INTERNAL) + spd_register(SPD_TYPE_EDO, 0x7, 256); + + if (gfxcard[0] == VID_INTERNAL) device_add(machine_get_vid_device(machine)); if (sound_card_current[0] == SOUND_INTERNAL) @@ -670,11 +669,10 @@ static const device_config_t d943_config[] = { .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d943/d943_oct96.bin", "" } }, { .name = "Version 4.05 Revision 1.03.943 (12/12/1996)", .internal_name = "d943_dec96", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d943/d943_dec96.bin", "" } }, - { .name = "Version 4.05 Revision 1.05.943 (09/04/1997)", .internal_name = "d943_sept97", .bios_type = BIOS_NORMAL, + { .name = "Version 4.05 Revision 1.05.943 (09/04/1997)", .internal_name = "d943_sept97", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d943/d943_sept97.bin", "" } }, { .name = "Version 4.05 Revision 1.06.943 (10/29/1997)", .internal_name = "d943_oct97", .bios_type = BIOS_NORMAL, .files_no = 1, .local = 0, .size = 131072, .files = { "roms/machines/d943/d943_oct97.bin", "" } }, - }, }, { .name = "", .description = "", .type = CONFIG_END } @@ -691,7 +689,7 @@ const device_t d943_device = { .init = NULL, .close = NULL, .reset = NULL, - .available = NULL, + .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = &d943_config[0] diff --git a/src/machine/m_elt.c b/src/machine/m_elt.c index 812755898..628333aba 100644 --- a/src/machine/m_elt.c +++ b/src/machine/m_elt.c @@ -58,13 +58,13 @@ static void elt_vid_off_poll(void *priv) { cga_t *cga = priv; - uint8_t hdisp = cga->crtc[1]; + uint8_t hdisp = cga->crtc[CGA_CRTC_HDISP]; /* Don't display anything. * TODO: Do something less stupid to emulate backlight off. */ - cga->crtc[1] = 0; + cga->crtc[CGA_CRTC_HDISP] = 0; cga_poll(cga); - cga->crtc[1] = hdisp; + cga->crtc[CGA_CRTC_HDISP] = hdisp; } static void diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index f2da2e2b5..30a5e609a 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -48,11 +48,10 @@ #include <86box/snd_sn76489.h> #include <86box/video.h> #include <86box/vid_cga_comp.h> +#include <86box/m_pcjr.h> #include <86box/machine.h> #include <86box/plat_unused.h> -#define PCJR_RGB 0 -#define PCJR_COMPOSITE 1 #define STAT_PARITY 0x80 #define STAT_RTIMEOUT 0x40 @@ -63,49 +62,10 @@ #define STAT_IFULL 0x02 #define STAT_OFULL 0x01 -typedef struct pcjr_t { - /* Video Controller stuff. */ - mem_mapping_t mapping; - uint8_t crtc[32]; - int crtcreg; - int array_index; - uint8_t array[32]; - int array_ff; - int memctrl; - uint8_t stat; - int addr_mode; - uint8_t *vram; - uint8_t *b8000; - int linepos; - int displine; - int sc; - int vc; - int dispon; - int con; - int cursoron; - int blink; - int vsynctime; - int fullchange; - int vadj; - uint16_t ma; - uint16_t maback; - uint64_t dispontime; - uint64_t dispofftime; - pc_timer_t timer; - int firstline; - int lastline; - int composite; - int apply_hd; - /* Keyboard Controller stuff. */ - int latched; - int data; - int serial_data[44]; - int serial_pos; - uint8_t pa; - uint8_t pb; - pc_timer_t send_delay_timer; -} pcjr_t; +static uint8_t key_queue[16]; +static int key_queue_start = 0; +static int key_queue_end = 0; /*PCjr keyboard has no escape scancodes, and no scancodes beyond 54 Map right alt to 54h (FN) */ @@ -626,643 +586,6 @@ const scancode scancode_pcjr[512] = { // clang-format on }; -static video_timings_t timing_dram = { VIDEO_BUS, 0, 0, 0, 0, 0, 0 }; /*No additional waitstates*/ - -static uint8_t crtcmask[32] = { - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, - 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static uint8_t key_queue[16]; -static int key_queue_start = 0; -static int key_queue_end = 0; - -static void -recalc_address(pcjr_t *pcjr) -{ - uint8_t masked_memctrl = pcjr->memctrl; - - /* According to the Technical Reference, bits 2 and 5 are - ignored if there is only 64k of RAM and there are only - 4 pages. */ - if (mem_size < 128) - masked_memctrl &= ~0x24; - - if ((pcjr->memctrl & 0xc0) == 0xc0) { - pcjr->vram = &ram[(masked_memctrl & 0x06) << 14]; - pcjr->b8000 = &ram[(masked_memctrl & 0x30) << 11]; - } else { - pcjr->vram = &ram[(masked_memctrl & 0x07) << 14]; - pcjr->b8000 = &ram[(masked_memctrl & 0x38) << 11]; - } -} - -static void -recalc_timings(pcjr_t *pcjr) -{ - double _dispontime; - double _dispofftime; - double disptime; - - if (pcjr->array[0] & 1) { - disptime = pcjr->crtc[0] + 1; - _dispontime = pcjr->crtc[1]; - } else { - disptime = (pcjr->crtc[0] + 1) << 1; - _dispontime = pcjr->crtc[1] << 1; - } - - _dispofftime = disptime - _dispontime; - _dispontime *= CGACONST; - _dispofftime *= CGACONST; - pcjr->dispontime = (uint64_t) (_dispontime); - pcjr->dispofftime = (uint64_t) (_dispofftime); -} - -static int -vid_get_h_overscan_size(pcjr_t *pcjr) -{ - int ret; - - if (pcjr->array[0] & 1) - ret = 128; - else - ret = 256; - - return ret; -} - -static void -vid_out(uint16_t addr, uint8_t val, void *priv) -{ - pcjr_t *pcjr = (pcjr_t *) priv; - uint8_t old; - - switch (addr) { - case 0x3d0: - case 0x3d2: - case 0x3d4: - case 0x3d6: - pcjr->crtcreg = val & 0x1f; - return; - - case 0x3d1: - case 0x3d3: - case 0x3d5: - case 0x3d7: - old = pcjr->crtc[pcjr->crtcreg]; - pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; - if (pcjr->crtcreg == 2) - overscan_x = vid_get_h_overscan_size(pcjr); - if (old != val) { - if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) { - pcjr->fullchange = changeframecount; - recalc_timings(pcjr); - } - } - return; - - case 0x3da: - if (!pcjr->array_ff) - pcjr->array_index = val & 0x1f; - else { - if (pcjr->array_index & 0x10) - val &= 0x0f; - pcjr->array[pcjr->array_index & 0x1f] = val; - if (!(pcjr->array_index & 0x1f)) - update_cga16_color(val); - } - pcjr->array_ff = !pcjr->array_ff; - break; - - case 0x3df: - pcjr->memctrl = val; - pcjr->pa = val; /* The PCjr BIOS expects the value written to 3DF to - then be readable from port 60, others it errors out - with only 64k RAM set (but somehow, still works with - 128k or more RAM). */ - pcjr->addr_mode = val >> 6; - recalc_address(pcjr); - break; - - default: - break; - } -} - -static uint8_t -vid_in(uint16_t addr, void *priv) -{ - pcjr_t *pcjr = (pcjr_t *) priv; - uint8_t ret = 0xff; - - switch (addr) { - case 0x3d0: - case 0x3d2: - case 0x3d4: - case 0x3d6: - ret = pcjr->crtcreg; - break; - - case 0x3d1: - case 0x3d3: - case 0x3d5: - case 0x3d7: - ret = pcjr->crtc[pcjr->crtcreg]; - break; - - case 0x3da: - pcjr->array_ff = 0; - pcjr->stat ^= 0x10; - ret = pcjr->stat; - break; - - default: - break; - } - - return ret; -} - -static void -vid_write(uint32_t addr, uint8_t val, void *priv) -{ - pcjr_t *pcjr = (pcjr_t *) priv; - - if (pcjr->memctrl == -1) - return; - - pcjr->b8000[addr & 0x3fff] = val; -} - -static uint8_t -vid_read(uint32_t addr, void *priv) -{ - const pcjr_t *pcjr = (pcjr_t *) priv; - - if (pcjr->memctrl == -1) - return 0xff; - - return (pcjr->b8000[addr & 0x3fff]); -} - -static int -vid_get_h_overscan_delta(pcjr_t *pcjr) -{ - int def; - int coef; - int ret; - - switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { - case 0x13: /*320x200x16*/ - def = 0x56; - coef = 8; - break; - case 0x12: /*160x200x16*/ - def = 0x2c; /* I'm going to assume a datasheet erratum here. */ - coef = 16; - break; - case 0x03: /*640x200x4*/ - def = 0x56; - coef = 8; - break; - case 0x01: /*80 column text*/ - def = 0x5a; - coef = 8; - break; - case 0x00: /*40 column text*/ - default: - def = 0x2c; - coef = 16; - break; - case 0x02: /*320x200x4*/ - def = 0x2b; - coef = 16; - break; - case 0x102: /*640x200x2*/ - def = 0x2b; - coef = 16; - break; - } - - ret = pcjr->crtc[0x02] - def; - - if (ret < -8) - ret = -8; - - if (ret > 8) - ret = 8; - - return ret * coef; -} - -static void -vid_blit_h_overscan(pcjr_t *pcjr) -{ - int cols = (pcjr->array[2] & 0xf) + 16;; - int y0 = pcjr->firstline << 1; - int y = (pcjr->lastline << 1) + 16; - int ho_s = vid_get_h_overscan_size(pcjr); - int i; - int x; - - if (pcjr->array[0] & 1) - x = (pcjr->crtc[1] << 3) + ho_s; - else - x = (pcjr->crtc[1] << 4) + ho_s; - - for (i = 0; i < 16; i++) { - hline(buffer32, 0, y0 + i, x, cols); - hline(buffer32, 0, y + i, x, cols); - - if (pcjr->composite) { - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[y0 + i]); - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[y + i]); - } else { - video_process_8(x, y0 + i); - video_process_8(x, y + i); - } - } -} - -static void -vid_poll(void *priv) -{ - pcjr_t *pcjr = (pcjr_t *) priv; - uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x; - int xs_temp; - int ys_temp; - int oldvc; - uint8_t chr; - uint8_t attr; - uint16_t dat; - int cols[4]; - int oldsc; - int l = (pcjr->displine << 1) + 16; - int ho_s = vid_get_h_overscan_size(pcjr); - int ho_d = vid_get_h_overscan_delta(pcjr) + (ho_s / 2); - - if (!pcjr->linepos) { - timer_advance_u64(&pcjr->timer, pcjr->dispofftime); - pcjr->stat &= ~1; - pcjr->linepos = 1; - oldsc = pcjr->sc; - if ((pcjr->crtc[8] & 3) == 3) - pcjr->sc = (pcjr->sc << 1) & 7; - if (pcjr->dispon) { - uint16_t offset = 0; - uint16_t mask = 0x1fff; - - if (pcjr->displine < pcjr->firstline) { - pcjr->firstline = pcjr->displine; - video_wait_for_buffer(); - } - pcjr->lastline = pcjr->displine; - cols[0] = (pcjr->array[2] & 0xf) + 16; - - if (pcjr->array[0] & 1) { - hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, cols[0]); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, cols[0]); - } else { - hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, cols[0]); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, cols[0]); - } - - switch (pcjr->addr_mode) { - case 0: /*Alpha*/ - offset = 0; - mask = 0x3fff; - break; - case 1: /*Low resolution graphics*/ - offset = (pcjr->sc & 1) * 0x2000; - break; - case 3: /*High resolution graphics*/ - offset = (pcjr->sc & 3) * 0x2000; - break; - default: - break; - } - switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { - case 0x13: /*320x200x16*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 3) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - pcjr->ma++; - buffer32->line[l][ef_x] = buffer32->line[l][ef_x + 1] = - buffer32->line[l + 1][ef_x] = buffer32->line[l + 1][ef_x + 1] = - pcjr->array[((dat >> 12) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 2] = buffer32->line[l][ef_x + 3] = - buffer32->line[l + 1][ef_x + 2] = buffer32->line[l + 1][ef_x + 3] = - pcjr->array[((dat >> 8) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 4] = buffer32->line[l][ef_x + 5] = - buffer32->line[l + 1][ef_x + 4] = buffer32->line[l + 1][ef_x + 5] = - pcjr->array[((dat >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 6] = buffer32->line[l][ef_x + 7] = - buffer32->line[l + 1][ef_x + 6] = buffer32->line[l + 1][ef_x + 7] = - pcjr->array[(dat & pcjr->array[1] & 0x0f) + 16] + 16; - } - break; - case 0x12: /*160x200x16*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 4) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - pcjr->ma++; - buffer32->line[l][ef_x] = buffer32->line[l][ef_x + 1] = - buffer32->line[l][ef_x + 2] = buffer32->line[l][ef_x + 3] = - buffer32->line[l + 1][ef_x] = buffer32->line[l + 1][ef_x + 1] = - buffer32->line[l + 1][ef_x + 2] = buffer32->line[l + 1][ef_x + 3] = - pcjr->array[((dat >> 12) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 4] = buffer32->line[l][ef_x + 5] = - buffer32->line[l][ef_x + 6] = buffer32->line[l][ef_x + 7] = - buffer32->line[l + 1][ef_x + 4] = buffer32->line[l + 1][ef_x + 5] = - buffer32->line[l + 1][ef_x + 6] = buffer32->line[l + 1][ef_x + 7] = - pcjr->array[((dat >> 8) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 8] = buffer32->line[l][ef_x + 9] = - buffer32->line[l][ef_x + 10] = buffer32->line[l][ef_x + 11] = - buffer32->line[l + 1][ef_x + 8] = buffer32->line[l + 1][ef_x + 9] = - buffer32->line[l + 1][ef_x + 10] = buffer32->line[l + 1][ef_x + 11] = - pcjr->array[((dat >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; - buffer32->line[l][ef_x + 12] = buffer32->line[l][ef_x + 13] = - buffer32->line[l][ef_x + 14] = buffer32->line[l][ef_x + 15] = - buffer32->line[l + 1][ef_x + 12] = buffer32->line[l + 1][ef_x + 13] = - buffer32->line[l + 1][ef_x + 14] = buffer32->line[l + 1][ef_x + 15] = - pcjr->array[(dat & pcjr->array[1] & 0x0f) + 16] + 16; - } - break; - case 0x03: /*640x200x4*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 3) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset]; - pcjr->ma++; - for (uint8_t c = 0; c < 8; c++) { - chr = (dat >> 7) & 1; - chr |= ((dat >> 14) & 2); - buffer32->line[l][ef_x + c] = buffer32->line[l + 1][ef_x + c] = - pcjr->array[(chr & pcjr->array[1] & 0x0f) + 16] + 16; - dat <<= 1; - } - } - break; - case 0x01: /*80 column text*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 3) + ho_d; - chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; - attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); - if (pcjr->array[3] & 4) { - cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; - cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1] & 0x0f) + 16] + 16; - if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; - cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; - } - if (pcjr->sc & 8) - for (uint8_t c = 0; c < 8; c++) - buffer32->line[l][ef_x + c] = - buffer32->line[l + 1][ef_x + c] = cols[0]; - else - for (uint8_t c = 0; c < 8; c++) - buffer32->line[l][ef_x + c] = - buffer32->line[l + 1][ef_x + c] = - cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - if (drawcursor) - for (uint8_t c = 0; c < 8; c++) { - buffer32->line[l][ef_x + c] ^= 15; - buffer32->line[l + 1][ef_x + c] ^= 15; - } - pcjr->ma++; - } - break; - case 0x00: /*40 column text*/ - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 4) + ho_d; - chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; - attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); - if (pcjr->array[3] & 4) { - cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; - cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1] & 0x0f) + 16] + 16; - if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; - cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; - } - pcjr->ma++; - if (pcjr->sc & 8) - for (uint8_t c = 0; c < 8; c++) - buffer32->line[l][ef_x + (c << 1)] = - buffer32->line[l][ef_x + (c << 1) + 1] = - buffer32->line[l + 1][ef_x + (c << 1)] = - buffer32->line[l + 1][ef_x + (c << 1) + 1] = cols[0]; - else - for (uint8_t c = 0; c < 8; c++) - buffer32->line[l][ef_x + (c << 1)] = - buffer32->line[l][ef_x + (c << 1) + 1] = - buffer32->line[l + 1][ef_x + (c << 1)] = - buffer32->line[l + 1][ef_x + (c << 1) + 1] = - cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - if (drawcursor) - for (uint8_t c = 0; c < 16; c++) { - buffer32->line[l][ef_x + c] ^= 15; - buffer32->line[l + 1][ef_x + c] ^= 15; - } - } - break; - case 0x02: /*320x200x4*/ - cols[0] = pcjr->array[0 + 16] + 16; - cols[1] = pcjr->array[1 + 16] + 16; - cols[2] = pcjr->array[2 + 16] + 16; - cols[3] = pcjr->array[3 + 16] + 16; - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 4) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - pcjr->ma++; - for (uint8_t c = 0; c < 8; c++) { - buffer32->line[l][ef_x + (c << 1)] = - buffer32->line[l][ef_x + (c << 1) + 1] = - buffer32->line[l + 1][ef_x + (c << 1)] = - buffer32->line[l + 1][ef_x + (c << 1) + 1] = cols[dat >> 14]; - dat <<= 2; - } - } - break; - case 0x102: /*640x200x2*/ - cols[0] = pcjr->array[0 + 16] + 16; - cols[1] = pcjr->array[1 + 16] + 16; - for (x = 0; x < pcjr->crtc[1]; x++) { - int ef_x = (x << 4) + ho_d; - dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | - pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; - pcjr->ma++; - for (uint8_t c = 0; c < 16; c++) { - buffer32->line[l][ef_x + c] = buffer32->line[l + 1][ef_x + c] = - cols[dat >> 15]; - dat <<= 1; - } - } - break; - - default: - break; - } - } else { - if (pcjr->array[3] & 4) { - if (pcjr->array[0] & 1) { - hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, (pcjr->array[2] & 0xf) + 16); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, (pcjr->array[2] & 0xf) + 16); - } else { - hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, (pcjr->array[2] & 0xf) + 16); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, (pcjr->array[2] & 0xf) + 16); - } - } else { - cols[0] = pcjr->array[0 + 16] + 16; - if (pcjr->array[0] & 1) { - hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, cols[0]); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, cols[0]); - } else { - hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, cols[0]); - hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, cols[0]); - } - } - } - if (pcjr->array[0] & 1) - x = (pcjr->crtc[1] << 3) + ho_s; - else - x = (pcjr->crtc[1] << 4) + ho_s; - if (pcjr->composite) { - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[l]); - Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[l + 1]); - } else { - video_process_8(x, l); - video_process_8(x, l + 1); - } - pcjr->sc = oldsc; - if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) { - pcjr->stat |= 8; - } - pcjr->displine++; - if (pcjr->displine >= 360) - pcjr->displine = 0; - } else { - timer_advance_u64(&pcjr->timer, pcjr->dispontime); - if (pcjr->dispon) - pcjr->stat |= 1; - pcjr->linepos = 0; - if (pcjr->vsynctime) { - pcjr->vsynctime--; - if (!pcjr->vsynctime) { - pcjr->stat &= ~8; - } - } - if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) { - pcjr->con = 0; - } - if (pcjr->vadj) { - pcjr->sc++; - pcjr->sc &= 31; - pcjr->ma = pcjr->maback; - pcjr->vadj--; - if (!pcjr->vadj) { - pcjr->dispon = 1; - pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; - pcjr->sc = 0; - } - } else if (pcjr->sc == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == (pcjr->crtc[9] >> 1))) { - pcjr->maback = pcjr->ma; - pcjr->sc = 0; - oldvc = pcjr->vc; - pcjr->vc++; - pcjr->vc &= 127; - if (pcjr->vc == pcjr->crtc[6]) - pcjr->dispon = 0; - if (oldvc == pcjr->crtc[4]) { - pcjr->vc = 0; - pcjr->vadj = pcjr->crtc[5]; - if (!pcjr->vadj) - pcjr->dispon = 1; - if (!pcjr->vadj) - pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; - if ((pcjr->crtc[10] & 0x60) == 0x20) - pcjr->cursoron = 0; - else - pcjr->cursoron = pcjr->blink & 16; - } - if (pcjr->vc == pcjr->crtc[7]) { - pcjr->dispon = 0; - pcjr->displine = 0; - pcjr->vsynctime = 16; - picint(1 << 5); - if (pcjr->crtc[7]) { - if (pcjr->array[0] & 1) - x = (pcjr->crtc[1] << 3) + ho_s; - else - x = (pcjr->crtc[1] << 4) + ho_s; - pcjr->lastline++; - - xs_temp = x; - ys_temp = (pcjr->lastline - pcjr->firstline) << 1; - - if ((xs_temp > 0) && (ys_temp > 0)) { - int actual_ys = ys_temp; - - if (xs_temp < 64) - xs_temp = 656; - if (ys_temp < 32) - ys_temp = 400; - if (!enable_overscan) - xs_temp -= ho_s; - - if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { - xsize = xs_temp; - ysize = ys_temp; - - set_screen_size(xsize, ysize + (enable_overscan ? 32 : 0)); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - - vid_blit_h_overscan(pcjr); - - if (enable_overscan) { - video_blit_memtoscreen(0, pcjr->firstline << 1, - xsize, actual_ys + 32); - } else if (pcjr->apply_hd) { - video_blit_memtoscreen(ho_s / 2, (pcjr->firstline << 1) + 16, - xsize, actual_ys); - } else { - video_blit_memtoscreen(ho_d, (pcjr->firstline << 1) + 16, - xsize, actual_ys); - } - } - - frames++; - video_res_x = xsize; - video_res_y = ysize; - } - pcjr->firstline = 1000; - pcjr->lastline = 0; - pcjr->blink++; - } - } else { - pcjr->sc++; - pcjr->sc &= 31; - pcjr->ma = pcjr->maback; - } - if (pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1))) - pcjr->con = 1; - } -} static void kbd_write(uint16_t port, uint8_t val, void *priv) @@ -1433,35 +756,7 @@ speed_changed(void *priv) { pcjr_t *pcjr = (pcjr_t *) priv; - recalc_timings(pcjr); -} - -static void -pcjr_vid_init(pcjr_t *pcjr) -{ - int display_type; - - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); - - pcjr->memctrl = -1; - if (mem_size < 128) - pcjr->memctrl &= ~0x24; - - display_type = device_get_config_int("display_type"); - pcjr->composite = (display_type != PCJR_RGB); - pcjr->apply_hd = device_get_config_int("apply_hd"); - overscan_x = 256; - overscan_y = 32; - - mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, - vid_read, NULL, NULL, - vid_write, NULL, NULL, NULL, 0, pcjr); - io_sethandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); - timer_add(&pcjr->timer, vid_poll, pcjr, 1); - - cga_palette = 0; - cgapal_rebuild(); + pcjr_recalc_timings(pcjr); } void @@ -1487,9 +782,11 @@ static const device_config_t pcjr_config[] = { .file_filter = "", .spinner = { 0 }, .selection = { - { .description = "RGB", .value = PCJR_RGB }, - { .description = "Composite", .value = PCJR_COMPOSITE }, - { .description = "" } + { .description = "RGB", .value = PCJR_RGB }, + { .description = "Composite", .value = PCJR_COMPOSITE }, + { .description = "RGB (no brown)", .value = PCJR_RGB_NO_BROWN }, + { .description = "RGB (IBM 5153)", .value = PCJR_RGB_IBM_5153 }, + { .description = "" } } }, { diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 4d0768378..69200febe 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -44,12 +44,9 @@ #include <86box/video.h> #include <86box/vid_cga_comp.h> #include <86box/machine.h> +#include <86box/m_tandy.h> #include <86box/plat_unused.h> -enum { - TANDY_RGB = 0, - TANDY_COMPOSITE -}; enum { TYPE_TANDY = 0, @@ -65,79 +62,6 @@ enum { EEPROM_WRITE }; -typedef struct t1kvid_t { - mem_mapping_t mapping; - mem_mapping_t vram_mapping; - - uint8_t crtc[32]; - int crtcreg; - - int array_index; - uint8_t array[256]; - int memctrl; - uint8_t mode; - uint8_t col; - uint8_t stat; - - uint8_t *vram; - uint8_t *b8000; - uint32_t b8000_mask; - uint32_t b8000_limit; - uint8_t planar_ctrl; - uint8_t lp_strobe; - - int linepos; - int displine; - int sc; - int vc; - int dispon; - int con; - int cursoron; - int blink; - int fullchange; - int vsynctime; - int vadj; - uint16_t ma; - uint16_t maback; - - uint64_t dispontime; - uint64_t dispofftime; - pc_timer_t timer; - int firstline; - int lastline; - - int composite; -} t1kvid_t; - -typedef struct t1keep_t { - char *path; - - int state; - int count; - int addr; - int clk; - uint16_t data; - uint16_t store[64]; -} t1keep_t; - -typedef struct tandy_t { - mem_mapping_t ram_mapping; - mem_mapping_t rom_mapping; /* SL2 */ - - uint8_t *rom; /* SL2 */ - uint8_t ram_bank; - uint8_t rom_bank; /* SL2 */ - int rom_offset; /* SL2 */ - - uint32_t base; - uint32_t mask; - int is_hx; - int is_sl2; - - t1kvid_t *vid; -} tandy_t; - -static video_timings_t timing_dram = { VIDEO_BUS, 0, 0, 0, 0, 0, 0 }; /*No additional waitstates*/ static const scancode scancode_tandy[512] = { // clang-format off @@ -655,22 +579,8 @@ static const scancode scancode_tandy[512] = { { .mk = { 0 }, .brk = { 0 } } /* 1ff */ // clang-format on }; -static uint8_t crtcmask[32] = { - 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, - 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static uint8_t crtcmask_sl[32] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, - 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; -static int eep_data_out; -static uint8_t vid_in(uint16_t addr, void *priv); -static void vid_out(uint16_t addr, uint8_t val, void *priv); +static int eep_data_out; #ifdef ENABLE_TANDY_LOG int tandy_do_log = ENABLE_TANDY_LOG; @@ -690,762 +600,7 @@ tandy_log(const char *fmt, ...) # define tandy_log(fmt, ...) #endif -static void -recalc_mapping(tandy_t *dev) -{ - t1kvid_t *vid = dev->vid; - mem_mapping_disable(&vid->mapping); - io_removehandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, dev); - - if (vid->planar_ctrl & 4) { - mem_mapping_enable(&vid->mapping); - if (vid->array[5] & 1) - mem_mapping_set_addr(&vid->mapping, 0xa0000, 0x10000); - else - mem_mapping_set_addr(&vid->mapping, 0xb8000, 0x8000); - io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, dev); - } -} - -static void -recalc_timings(tandy_t *dev) -{ - t1kvid_t *vid = dev->vid; - - double _dispontime; - double _dispofftime; - double disptime; - - if (vid->mode & 1) { - disptime = vid->crtc[0] + 1; - _dispontime = vid->crtc[1]; - } else { - disptime = (vid->crtc[0] + 1) << 1; - _dispontime = vid->crtc[1] << 1; - } - - _dispofftime = disptime - _dispontime; - _dispontime *= CGACONST; - _dispofftime *= CGACONST; - vid->dispontime = (uint64_t) (_dispontime); - vid->dispofftime = (uint64_t) (_dispofftime); -} - -static void -recalc_address(tandy_t *dev) -{ - t1kvid_t *vid = dev->vid; - - if ((vid->memctrl & 0xc0) == 0xc0) { - vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; - vid->b8000_mask = 0x7fff; - } else { - vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; - vid->b8000_mask = 0x3fff; - } -} - -static void -recalc_address_sl(tandy_t *dev) -{ - t1kvid_t *vid = dev->vid; - - vid->b8000_limit = 0x8000; - - if (vid->array[5] & 1) { - vid->vram = &ram[((vid->memctrl & 0x04) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x20) << 11) + dev->base]; - } else if ((vid->memctrl & 0xc0) == 0xc0) { - vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; - } else { - vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; - vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; - if ((vid->memctrl & 0x38) == 0x38) - vid->b8000_limit = 0x4000; - } -} - -static void -vid_update_latch(t1kvid_t *vid) -{ - uint32_t lp_latch = vid->displine * vid->crtc[1]; - - vid->crtc[0x10] = (lp_latch >> 8) & 0x3f; - vid->crtc[0x11] = lp_latch & 0xff; -} - -static void -vid_out(uint16_t addr, uint8_t val, void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - t1kvid_t *vid = dev->vid; - uint8_t old; - - if ((addr >= 0x3d0) && (addr <= 0x3d7)) - addr = (addr & 0xff9) | 0x004; - - switch (addr) { - case 0x03d4: - vid->crtcreg = val & 0x1f; - break; - - case 0x03d5: - old = vid->crtc[vid->crtcreg]; - if (dev->is_sl2) - vid->crtc[vid->crtcreg] = val & crtcmask_sl[vid->crtcreg]; - else - vid->crtc[vid->crtcreg] = val & crtcmask[vid->crtcreg]; - if (old != val) { - if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { - vid->fullchange = changeframecount; - recalc_timings(dev); - } - } - break; - - case 0x03d8: - old = vid->mode; - vid->mode = val; - if ((old ^ val) & 0x01) - recalc_timings(dev); - if (!dev->is_sl2) - update_cga16_color(vid->mode); - break; - - case 0x03d9: - vid->col = val; - break; - - case 0x03da: - vid->array_index = val & 0x1f; - break; - - case 0x3db: - if (!dev->is_sl2 && (vid->lp_strobe == 1)) - vid->lp_strobe = 0; - break; - - case 0x3dc: - if (!dev->is_sl2 && (vid->lp_strobe == 0)) { - vid->lp_strobe = 1; - vid_update_latch(vid); - } - break; - - case 0x03de: - if (vid->array_index & 16) - val &= 0xf; - vid->array[vid->array_index & 0x1f] = val; - if (dev->is_sl2) { - if ((vid->array_index & 0x1f) == 5) { - recalc_mapping(dev); - recalc_address_sl(dev); - } - } - break; - - case 0x03df: - vid->memctrl = val; - if (dev->is_sl2) - recalc_address_sl(dev); - else - recalc_address(dev); - break; - - case 0x0065: - if (val == 8) - return; /*Hack*/ - vid->planar_ctrl = val; - recalc_mapping(dev); - break; - - default: - break; - } -} - -static uint8_t -vid_in(uint16_t addr, void *priv) -{ - const tandy_t *dev = (tandy_t *) priv; - t1kvid_t *vid = dev->vid; - uint8_t ret = 0xff; - - if ((addr >= 0x3d0) && (addr <= 0x3d7)) - addr = (addr & 0xff9) | 0x004; - - switch (addr) { - case 0x03d4: - ret = vid->crtcreg; - break; - - case 0x03d5: - ret = vid->crtc[vid->crtcreg]; - break; - - case 0x03da: - ret = vid->stat; - break; - - case 0x3db: - if (!dev->is_sl2 && (vid->lp_strobe == 1)) - vid->lp_strobe = 0; - break; - - case 0x3dc: - if (!dev->is_sl2 && (vid->lp_strobe == 0)) { - vid->lp_strobe = 1; - vid_update_latch(vid); - } - break; - - default: - break; - } - - return ret; -} - -static void -vid_write(uint32_t addr, uint8_t val, void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - t1kvid_t *vid = dev->vid; - - if (vid->memctrl == -1) - return; - - if (dev->is_sl2) { - if (vid->array[5] & 1) - vid->b8000[addr & 0xffff] = val; - else { - if ((addr & 0x7fff) < vid->b8000_limit) - vid->b8000[addr & 0x7fff] = val; - } - } else { - vid->b8000[addr & vid->b8000_mask] = val; - } -} - -static uint8_t -vid_read(uint32_t addr, void *priv) -{ - const tandy_t *dev = (tandy_t *) priv; - const t1kvid_t *vid = dev->vid; - - if (vid->memctrl == -1) - return 0xff; - - if (dev->is_sl2) { - if (vid->array[5] & 1) - return (vid->b8000[addr & 0xffff]); - if ((addr & 0x7fff) < vid->b8000_limit) - return (vid->b8000[addr & 0x7fff]); - else - return 0xff; - } else { - return (vid->b8000[addr & vid->b8000_mask]); - } -} - -static void -vid_poll(void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - t1kvid_t *vid = dev->vid; - uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x; - int c; - int xs_temp; - int ys_temp; - int oldvc; - uint8_t chr; - uint8_t attr; - uint16_t dat; - int cols[4]; - int col; - int oldsc; - - if (!vid->linepos) { - timer_advance_u64(&vid->timer, vid->dispofftime); - vid->stat |= 1; - vid->linepos = 1; - oldsc = vid->sc; - if ((vid->crtc[8] & 3) == 3) - vid->sc = (vid->sc << 1) & 7; - if (vid->dispon) { - if (vid->displine < vid->firstline) { - vid->firstline = vid->displine; - video_wait_for_buffer(); - } - vid->lastline = vid->displine; - cols[0] = (vid->array[2] & 0xf) + 16; - for (c = 0; c < 8; c++) { - if (vid->array[3] & 4) { - buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = cols[0]; - if (vid->mode & 1) { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = cols[0]; - } else { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = cols[0]; - } - } else if ((vid->mode & 0x12) == 0x12) { - buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = 0; - if (vid->mode & 1) { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = 0; - } else { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = 0; - } - } else { - buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->col & 15) + 16; - if (vid->mode & 1) { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; - } else { - buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; - } - } - } - if (dev->is_sl2 && (vid->array[5] & 1)) { /*640x200x16*/ - for (x = 0; x < vid->crtc[1] * 2; x++) { - dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | vid->vram[((vid->ma << 1) + 1) & 0xffff]; - vid->ma++; - buffer32->line[vid->displine << 1][(x << 2) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 8] = vid->array[((dat >> 12) & 0xf) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 2) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 9] = vid->array[((dat >> 8) & 0xf) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 2) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 10] = vid->array[((dat >> 4) & 0xf) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 2) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 11] = vid->array[(dat & 0xf) + 16] + 16; - } - } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; - vid->ma++; - buffer32->line[vid->displine << 1][(x << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8] = buffer32->line[vid->displine << 1][(x << 3) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 3) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 10] = buffer32->line[vid->displine << 1][(x << 3) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 3) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 12] = buffer32->line[vid->displine << 1][(x << 3) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 3) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 14] = buffer32->line[vid->displine << 1][(x << 3) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 15] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; - } - } else if (vid->array[3] & 0x10) { /*160x200x16*/ - for (x = 0; x < vid->crtc[1]; x++) { - if (dev->is_sl2) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - } else { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; - } - vid->ma++; - buffer32->line[vid->displine << 1][(x << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 8] = buffer32->line[vid->displine << 1][(x << 4) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 9] = buffer32->line[vid->displine << 1][(x << 4) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 10] = buffer32->line[vid->displine << 1][(x << 4) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 4) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 12] = buffer32->line[vid->displine << 1][(x << 4) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 13] = buffer32->line[vid->displine << 1][(x << 4) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 14] = buffer32->line[vid->displine << 1][(x << 4) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 4) + 16] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 16] = buffer32->line[vid->displine << 1][(x << 4) + 17] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 17] = buffer32->line[vid->displine << 1][(x << 4) + 18] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 18] = buffer32->line[vid->displine << 1][(x << 4) + 19] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; - buffer32->line[vid->displine << 1][(x << 4) + 20] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 20] = buffer32->line[vid->displine << 1][(x << 4) + 21] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 21] = buffer32->line[vid->displine << 1][(x << 4) + 22] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 22] = buffer32->line[vid->displine << 1][(x << 4) + 23] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 23] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; - } - } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 8; c++) { - chr = (dat >> 6) & 2; - chr |= ((dat >> 15) & 1); - buffer32->line[vid->displine << 1][(x << 3) + 8 + c] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; - dat <<= 1; - } - } - } else if (vid->mode & 1) { - for (x = 0; x < vid->crtc[1]; x++) { - chr = vid->vram[(vid->ma << 1) & 0x3fff]; - attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->mode & 0x20) { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; - } - if (vid->sc & 8) { - for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[0]; - } - } else { - for (c = 0; c < 8; c++) { - if (vid->sc == 8) { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; - } else { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - } - } - if (drawcursor) { - for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 3) + c + 8] ^= 15; - buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] ^= 15; - } - } - vid->ma++; - } - } else if (!(vid->mode & 2)) { - for (x = 0; x < vid->crtc[1]; x++) { - chr = vid->vram[(vid->ma << 1) & 0x3fff]; - attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; - drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); - if (vid->mode & 0x20) { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; - if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) - cols[1] = cols[0]; - } else { - cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; - cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; - } - vid->ma++; - if (vid->sc & 8) { - for (c = 0; c < 8; c++) - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = cols[0]; - } else { - for (c = 0; c < 8; c++) { - if (vid->sc == 8) { - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; - } else { - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; - } - } - } - if (drawcursor) { - for (c = 0; c < 16; c++) { - buffer32->line[vid->displine << 1][(x << 4) + c + 8] ^= 15; - buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] ^= 15; - } - } - } - } else if (!(vid->mode & 16)) { - cols[0] = (vid->col & 15); - col = (vid->col & 16) ? 8 : 0; - if (vid->mode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; - } else if (vid->col & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; - } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; - } - cols[0] = vid->array[(cols[0] & vid->array[1]) + 16] + 16; - cols[1] = vid->array[(cols[1] & vid->array[1]) + 16] + 16; - cols[2] = vid->array[(cols[2] & vid->array[1]) + 16] + 16; - cols[3] = vid->array[(cols[3] & vid->array[1]) + 16] + 16; - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 8; c++) { - buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; - dat <<= 2; - } - } - } else { - cols[0] = 0; - cols[1] = vid->array[(vid->col & vid->array[1]) + 16] + 16; - for (x = 0; x < vid->crtc[1]; x++) { - dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; - vid->ma++; - for (c = 0; c < 16; c++) { - buffer32->line[vid->displine << 1][(x << 4) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] = cols[dat >> 15]; - dat <<= 1; - } - } - } - } else { - if (vid->array[3] & 4) { - if (vid->mode & 1) { - hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); - } else { - hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); - hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); - } - } else { - cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; - if (vid->mode & 1) { - hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, cols[0]); - hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, cols[0]); - } else { - hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, cols[0]); - hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, cols[0]); - } - } - } - - if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 16; - else - x = (vid->crtc[1] << 4) + 16; - if (!dev->is_sl2 && vid->composite) { - Composite_Process(vid->mode, 0, x >> 2, buffer32->line[vid->displine << 1]); - Composite_Process(vid->mode, 0, x >> 2, buffer32->line[(vid->displine << 1) + 1]); - } else { - video_process_8(x, vid->displine << 1); - video_process_8(x, (vid->displine << 1) + 1); - } - vid->sc = oldsc; - if (vid->vc == vid->crtc[7] && !vid->sc) - vid->stat |= 8; - vid->displine++; - if (vid->displine >= 360) - vid->displine = 0; - } else { - timer_advance_u64(&vid->timer, vid->dispontime); - if (vid->dispon) - vid->stat &= ~1; - vid->linepos = 0; - if (vid->vsynctime) { - vid->vsynctime--; - if (!vid->vsynctime) - vid->stat &= ~8; - } - if (vid->sc == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[11] & 31) >> 1))) { - vid->con = 0; - } - if (vid->vadj) { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; - vid->vadj--; - if (!vid->vadj) { - vid->dispon = 1; - if (dev->is_sl2 && (vid->array[5] & 1)) - vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); - else - vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; - vid->sc = 0; - } - } else if (vid->sc == vid->crtc[9] || ((vid->crtc[8] & 3) == 3 && vid->sc == (vid->crtc[9] >> 1))) { - vid->maback = vid->ma; - vid->sc = 0; - oldvc = vid->vc; - vid->vc++; - if (dev->is_sl2) - vid->vc &= 255; - else - vid->vc &= 127; - if (vid->vc == vid->crtc[6]) - vid->dispon = 0; - if (oldvc == vid->crtc[4]) { - vid->vc = 0; - vid->vadj = vid->crtc[5]; - if (!vid->vadj) - vid->dispon = 1; - if (!vid->vadj) { - if (dev->is_sl2 && (vid->array[5] & 1)) - vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); - else - vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; - } - if ((vid->crtc[10] & 0x60) == 0x20) - vid->cursoron = 0; - else - vid->cursoron = vid->blink & 16; - } - if (vid->vc == vid->crtc[7]) { - vid->dispon = 0; - vid->displine = 0; - vid->vsynctime = 16; - picint(1 << 5); - if (vid->crtc[7]) { - if (vid->mode & 1) - x = (vid->crtc[1] << 3) + 16; - else - x = (vid->crtc[1] << 4) + 16; - vid->lastline++; - - xs_temp = x; - ys_temp = (vid->lastline - vid->firstline) << 1; - - if ((xs_temp > 0) && (ys_temp > 0)) { - if (xs_temp < 64) - xs_temp = 656; - if (ys_temp < 32) - ys_temp = 400; - if (!enable_overscan) - xs_temp -= 16; - - if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { - xsize = xs_temp; - ysize = ys_temp; - set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - - if (enable_overscan) { - video_blit_memtoscreen(0, (vid->firstline - 4) << 1, - xsize, ((vid->lastline - vid->firstline) + 8) << 1); - } else { - video_blit_memtoscreen(8, vid->firstline << 1, - xsize, (vid->lastline - vid->firstline) << 1); - } - } - - frames++; - - video_res_x = xsize; - video_res_y = ysize; - if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ - video_res_x /= 2; - video_bpp = 4; - } else if (vid->array[3] & 0x10) { /*160x200x16*/ - video_res_x /= 4; - video_bpp = 4; - } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ - video_bpp = 2; - } else if (vid->mode & 1) { - video_res_x /= 8; - video_res_y /= vid->crtc[9] + 1; - video_bpp = 0; - } else if (!(vid->mode & 2)) { - video_res_x /= 16; - video_res_y /= vid->crtc[9] + 1; - video_bpp = 0; - } else if (!(vid->mode & 16)) { - video_res_x /= 2; - video_bpp = 2; - } else { - video_bpp = 1; - } - } - vid->firstline = 1000; - vid->lastline = 0; - vid->blink++; - } - } else { - vid->sc++; - vid->sc &= 31; - vid->ma = vid->maback; - } - if (vid->sc == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[10] & 31) >> 1))) - vid->con = 1; - } -} - -static void -vid_speed_changed(void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - - recalc_timings(dev); -} - -static void -vid_close(void *priv) -{ - tandy_t *dev = (tandy_t *) priv; - - free(dev->vid); - dev->vid = NULL; -} - -static void -vid_init(tandy_t *dev) -{ - int display_type; - t1kvid_t *vid; - - vid = calloc(1, sizeof(t1kvid_t)); - vid->memctrl = -1; - - video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); - - display_type = device_get_config_int("display_type"); - vid->composite = (display_type != TANDY_RGB); - - cga_comp_init(1); - - if (dev->is_sl2) { - vid->b8000_limit = 0x8000; - vid->planar_ctrl = 4; - overscan_x = overscan_y = 16; - - io_sethandler(0x0065, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, dev); - } else - vid->b8000_mask = 0x3fff; - - timer_add(&vid->timer, vid_poll, dev, 1); - mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, - vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, dev); - io_sethandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, dev); - - dev->vid = vid; -} - -const device_config_t vid_config[] = { - // clang-format off - { - .name = "display_type", - .description = "Display type", - .type = CONFIG_SELECTION, - .default_string = "", - .default_int = TANDY_RGB, - .file_filter = "", - .spinner = { 0 }, - .selection = { - { .description = "RGB", .value = TANDY_RGB }, - { .description = "Composite", .value = TANDY_COMPOSITE }, - { .description = "" } - } - }, - { .name = "", .description = "", .type = CONFIG_END } - // clang-format on -}; - -const device_t vid_device = { - .name = "Tandy 1000", - .internal_name = "tandy1000_video", - .flags = 0, - .local = 0, - .init = NULL, - .close = vid_close, - .reset = NULL, - .available = NULL, - .speed_changed = vid_speed_changed, - .force_redraw = NULL, - .config = vid_config -}; - -const device_t vid_device_hx = { - .name = "Tandy 1000 HX", - .internal_name = "tandy1000_hx_video", - .flags = 0, - .local = 0, - .init = NULL, - .close = vid_close, - .reset = NULL, - .available = NULL, - .speed_changed = vid_speed_changed, - .force_redraw = NULL, - .config = vid_config -}; - -const device_t vid_device_sl = { - .name = "Tandy 1000SL2", - .internal_name = "tandy1000_sl_video", - .flags = 0, - .local = 1, - .init = NULL, - .close = vid_close, - .reset = NULL, - .available = NULL, - .speed_changed = vid_speed_changed, - .force_redraw = NULL, - .config = NULL -}; static void eep_write(UNUSED(uint16_t addr), uint8_t val, void *priv) @@ -1630,12 +785,12 @@ tandy_write(uint16_t addr, uint8_t val, void *priv) } if (dev->is_hx) { io_removehandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, dev); + tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); if (val & 0x01) mem_mapping_disable(&dev->vid->mapping); else { io_sethandler(0x03d0, 16, - vid_in, NULL, NULL, vid_out, NULL, NULL, dev); + tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); mem_mapping_set_addr(&dev->vid->mapping, 0xb8000, 0x8000); } } else { @@ -1654,7 +809,7 @@ tandy_write(uint16_t addr, uint8_t val, void *priv) mem_mapping_set_addr(&dev->ram_mapping, ((val >> 1) & 7) * 128 * 1024, 0x20000); - recalc_address_sl(dev); + tandy_recalc_address_sl(dev); dev->ram_bank = val; break; @@ -1803,10 +958,10 @@ machine_tandy1k_init(const machine_t *model, int type) keyboard_set_table(scancode_tandy); io_sethandler(0x00a0, 1, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); - device_context(&vid_device); - vid_init(dev); + device_context(&tandy_1000_video_device); + tandy_vid_init(dev); device_context_restore(); - device_add_ex(&vid_device, dev); + device_add_ex(&tandy_1000_video_device, dev); device_add((type == TYPE_TANDY1000SX) ? &ncr8496_device : &sn76489_device); break; @@ -1815,10 +970,10 @@ machine_tandy1k_init(const machine_t *model, int type) keyboard_set_table(scancode_tandy); io_sethandler(0x00a0, 1, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); - device_context(&vid_device_hx); - vid_init(dev); + device_context(&tandy_1000hx_video_device); + tandy_vid_init(dev); device_context_restore(); - device_add_ex(&vid_device_hx, dev); + device_add_ex(&tandy_1000hx_video_device, dev); device_add(&ncr8496_device); device_add(&eep_1000hx_device); break; @@ -1828,10 +983,10 @@ machine_tandy1k_init(const machine_t *model, int type) init_rom(dev); io_sethandler(0xffe8, 8, tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev); - device_context(&vid_device_sl); - vid_init(dev); + device_context(&tandy_1000sl_video_device); + tandy_vid_init(dev); device_context_restore(); - device_add_ex(&vid_device_sl, dev); + device_add_ex(&tandy_1000sl_video_device, dev); device_add(&pssj_device); device_add(&eep_1000sl2_device); break; diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index d71d16c15..c94549463 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -39,6 +39,7 @@ #include <86box/keyboard.h> #include <86box/rom.h> #include <86box/machine.h> +#include <86box/nvr.h> #include <86box/chipset.h> #include <86box/port_6x.h> #include <86box/video.h> @@ -668,6 +669,34 @@ machine_xt_amixt_init(const machine_t *model) return ret; } +int +machine_xt_tuliptc8_init(const machine_t *model) +{ + int ret; + + ret = bios_load_linear("roms/machines/tuliptc8/tulip-bios_xt_compact_2.bin", + 0x000fc000, 16384, 0); + + if (bios_only || !ret) + return ret; + + device_add(&keyboard_xt_fe2010_device); + + if (fdc_current[0] == FDC_INTERNAL) + device_add(&fdc_at_device); + + machine_common_init(model); + + pit_devs[0].set_out_func(pit_devs[0].data, 1, pit_refresh_timer_xt); + + nmi_init(); + standalone_gameport_type = &gameport_device; + + device_add(&amstrad_megapc_nvr_device); + + return ret; +} + // TODO // Onboard EGA Graphics (NSI Logic EVC315-S on early boards STMicroelectronics EGA on later revisions) // RTC diff --git a/src/machine/m_xt_olivetti.c b/src/machine/m_xt_olivetti.c index acdb77fd1..8e37dce1f 100644 --- a/src/machine/m_xt_olivetti.c +++ b/src/machine/m_xt_olivetti.c @@ -1918,7 +1918,7 @@ m19_vid_out(uint16_t addr, uint8_t val, void *priv) /* activating plantronics mode */ if (addr == 0x3dd) { /* already in graphics mode */ - if ((val & 0x30) && (vid->ogc.cga.cgamode & 0x2)) + if ((val & 0x30) && (vid->ogc.cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) vid->mode = PLANTRONICS_MODE; else vid->mode = OLIVETTI_OGC_MODE; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 001d9cb8c..3f324f4d6 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -39,8 +39,10 @@ // Temporarily here till we move everything out into the right files extern const device_t pcjr_device; extern const device_t m19_vid_device; -extern const device_t vid_device; -extern const device_t vid_device_hx; +extern const device_t tandy_1000_video_device; +extern const device_t tandy_1000hx_video_device; +extern const device_t tandy_1000sl_video_device; + extern const device_t t1000_video_device; extern const device_t xi8088_device; extern const device_t cga_device; @@ -50,7 +52,6 @@ extern const device_t vid_pc2086_device; extern const device_t vid_pc3086_device; extern const device_t vid_200_device; extern const device_t vid_ppc512_device; -extern const device_t vid_device_sl; extern const device_t t1200_video_device; extern const device_t compaq_plasma_device; extern const device_t ps1_2011_device; @@ -70,6 +71,7 @@ extern const device_t d842_device; extern const device_t d943_device; extern const device_t dells333sl_device; extern const device_t hot433a_device; +extern const device_t pbl300sx_device; const machine_filter_t machine_types[] = { { "None", MACHINE_TYPE_NONE }, @@ -106,6 +108,7 @@ const machine_filter_t machine_chipsets[] = { { "Headland GC100A", MACHINE_CHIPSET_GC100A }, { "Headland GC103", MACHINE_CHIPSET_GC103 }, { "Headland HT18", MACHINE_CHIPSET_HT18 }, + { "ACC 2036", MACHINE_CHIPSET_ACC_2036 }, { "ACC 2168", MACHINE_CHIPSET_ACC_2168 }, { "ALi M1217", MACHINE_CHIPSET_ALI_M1217 }, { "ALi M6117", MACHINE_CHIPSET_ALI_M6117 }, @@ -149,7 +152,9 @@ const machine_filter_t machine_chipsets[] = { { "OPTi 391", MACHINE_CHIPSET_OPTI_391 }, { "OPTi 481", MACHINE_CHIPSET_OPTI_481 }, { "OPTi 493", MACHINE_CHIPSET_OPTI_493 }, - { "OPTi 495", MACHINE_CHIPSET_OPTI_495 }, + { "OPTi 495SLC", MACHINE_CHIPSET_OPTI_495SLC }, + { "OPTi 495SX", MACHINE_CHIPSET_OPTI_495SX }, + { "OPTi 498", MACHINE_CHIPSET_OPTI_498 }, { "OPTi 499", MACHINE_CHIPSET_OPTI_499 }, { "OPTi 895/802G", MACHINE_CHIPSET_OPTI_895_802G }, { "OPTi 547/597", MACHINE_CHIPSET_OPTI_547_597 }, @@ -1591,7 +1596,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &vid_device, + .vid_device = &tandy_1000_video_device, .snd_device = NULL, .net_device = NULL }, @@ -1630,7 +1635,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &vid_device_hx, + .vid_device = &tandy_1000hx_video_device, .snd_device = NULL, .net_device = NULL }, @@ -2025,6 +2030,45 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + { + .name = "[V20] Tulip PC Compact 2", + .internal_name = "tuliptc8", + .type = MACHINE_TYPE_8088, + .chipset = MACHINE_CHIPSET_DISCRETE, + .init = machine_xt_tuliptc8_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_8088, + .block = CPU_BLOCK(CPU_8088), + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PC, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 64, + .max = 640, + .step = 64 + }, + .nvrmask = 63, + .kbc_device = &keyboard_xtclone_device, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* 8086 Machines */ { @@ -2531,7 +2575,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = &vid_device_sl, + .vid_device = &tandy_1000sl_video_device, .snd_device = NULL, .net_device = NULL }, @@ -3416,6 +3460,47 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* No proper pictures of the KBC exist, though it seems to have the IBM AT KBC + firmware. */ + { + .name = "[C&T PC/AT] PC's Limited (Dell) 28608L/AT122", + .internal_name = "at122", + .type = MACHINE_TYPE_286, + .chipset = MACHINE_CHIPSET_CT_AT, + .init = machine_at_at122_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_286, + .block = CPU_BLOCK_NONE, + .min_bus = 6000000, + .max_bus = 12000000, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_FLAGS_NONE, + .ram = { + .min = 640, + .max = 16384, + .step = 128 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* No proper pictures of the KBC exist, though it seems to have the IBM AT KBC firmware. */ { @@ -3692,7 +3777,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = ¶dise_pvga1a_ncr3302_device, .snd_device = NULL, .net_device = NULL }, @@ -4300,6 +4385,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Most likely has Phonenix KBC firmware. */ + { + .name = "[ACC 2036] Packard Bell Legend 300SX", + .internal_name = "pbl300sx", + .type = MACHINE_TYPE_386SX, + .chipset = MACHINE_CHIPSET_ACC_2036, + .init = machine_at_pbl300sx_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386SX, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_PS2, + .flags = MACHINE_IDE | MACHINE_VIDEO, + .ram = { + .min = 1024, + .max = 16384, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = &pbl300sx_device, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &oti037_pbl300sx_device, + .snd_device = NULL, + .net_device = NULL + }, /* This has an AMIKey-2, which is an updated version of type 'H'. */ { .name = "[ALi M1217] Acrosser AR-B1374", @@ -5716,10 +5841,10 @@ const machine_t machines[] = { but the BIOS sends commands C9 without a parameter and D5, both of which are Phoenix MultiKey commands. */ { - .name = "[OPTi 495] U-Board OPTi 495SLC", + .name = "[OPTi 495SLC] U-Board OPTi 495SLC", .internal_name = "award495", .type = MACHINE_TYPE_386DX, - .chipset = MACHINE_CHIPSET_OPTI_495, + .chipset = MACHINE_CHIPSET_OPTI_495SLC, .init = machine_at_opti495_init, .p1_handler = NULL, .gpio_handler = NULL, @@ -5958,12 +6083,52 @@ const machine_t machines[] = { }, /* 386DX/486 machines */ + /* Has AMIKey F KBC firmware. The EFAR chipst is a rebrand of OPTi 495SX. */ + { + .name = "[OPTi 495SX] CAF Technology C747", + .internal_name = "c747", + .type = MACHINE_TYPE_386DX_486, + .chipset = MACHINE_CHIPSET_OPTI_495SX, + .init = machine_at_c747_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_386DX | CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 0 + }, + .bus_flags = MACHINE_AT, + .flags = MACHINE_APM | MACHINE_IDE, + .ram = { + .min = 1024, + .max = 32768, + .step = 1024 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = NULL, + .snd_device = NULL, + .net_device = NULL + }, /* Has AMIKey F KBC firmware. */ { - .name = "[OPTi 495] DataExpert SX495", + .name = "[OPTi 495SX] DataExpert SX495", .internal_name = "ami495", .type = MACHINE_TYPE_386DX_486, - .chipset = MACHINE_CHIPSET_OPTI_495, + .chipset = MACHINE_CHIPSET_OPTI_495SX, .init = machine_at_opti495_ami_init, .p1_handler = NULL, .gpio_handler = NULL, @@ -6000,10 +6165,10 @@ const machine_t machines[] = { }, /* Has AMIKey F KBC firmware (it's just the MR BIOS for the above machine). */ { - .name = "[OPTi 495] DataExpert SX495 (MR BIOS)", + .name = "[OPTi 495SX] DataExpert SX495 (MR BIOS)", .internal_name = "mr495", .type = MACHINE_TYPE_386DX_486, - .chipset = MACHINE_CHIPSET_OPTI_495, + .chipset = MACHINE_CHIPSET_OPTI_495SX, .init = machine_at_opti495_mr_init, .p1_handler = NULL, .gpio_handler = NULL, @@ -6325,10 +6490,10 @@ const machine_t machines[] = { /* Uses some variant of Phoenix MultiKey/42 as the Intel 8242 chip has a Phoenix copyright. */ { - .name = "[OPTi 495] Mylex MVI486", + .name = "[OPTi 498] Mylex MVI486", .internal_name = "mvi486", .type = MACHINE_TYPE_486, - .chipset = MACHINE_CHIPSET_OPTI_495, + .chipset = MACHINE_CHIPSET_OPTI_498, .init = machine_at_mvi486_init, .p1_handler = NULL, .gpio_handler = NULL, @@ -6484,6 +6649,46 @@ const machine_t machines[] = { .snd_device = NULL, .net_device = NULL }, + /* Has Phoenix KBC firmware. */ + { + .name = "[SiS 471] AST Advantage! 40xxd", + .internal_name = "advantage40xxd", + .type = MACHINE_TYPE_486, + .chipset = MACHINE_CHIPSET_SIS_471, + .init = machine_at_advantage40xxd_init, + .p1_handler = NULL, + .gpio_handler = NULL, + .available_flag = MACHINE_AVAILABLE, + .gpio_acpi_handler = NULL, + .cpu = { + .package = CPU_PKG_SOCKET1, + .block = CPU_BLOCK_NONE, + .min_bus = 0, + .max_bus = 0, + .min_voltage = 0, + .max_voltage = 0, + .min_multi = 0, + .max_multi = 2 + }, + .bus_flags = MACHINE_PS2_VLB, + .flags = MACHINE_IDE | MACHINE_VIDEO | MACHINE_APM, + .ram = { + .min = 4096, + .max = 36864, + .step = 4096 + }, + .nvrmask = 127, + .kbc_device = NULL, + .kbc_p1 = 0xff, + .gpio = 0xffffffff, + .gpio_acpi = 0xffffffff, + .device = NULL, + .fdc_device = NULL, + .sio_device = NULL, + .vid_device = &gd5424_onboard_device, + .snd_device = NULL, + .net_device = NULL + }, /* Has AMIKey F KBC firmware. */ { .name = "[Symphony SL42C460] DTK PKM-0031Y", @@ -9235,7 +9440,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &tgui9440_onboard_pci_device, .snd_device = NULL, .net_device = NULL }, @@ -9276,7 +9481,7 @@ const machine_t machines[] = { .device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = &gd5430_onboard_pci_device, .snd_device = NULL, .net_device = NULL }, diff --git a/src/mem/catalyst_flash.c b/src/mem/catalyst_flash.c index 00e2422a3..5c8812464 100644 --- a/src/mem/catalyst_flash.c +++ b/src/mem/catalyst_flash.c @@ -29,6 +29,7 @@ #include <86box/timer.h> #include <86box/nvr.h> #include <86box/plat.h> +#include <86box/plat_fallthrough.h> #define FLAG_WORD 4 #define FLAG_BXB 2 @@ -44,21 +45,22 @@ enum { }; enum { - CMD_SET_READ = 0x00, - CMD_READ_SIGNATURE = 0x90, - CMD_ERASE = 0x20, - CMD_ERASE_CONFIRM = 0x20, - CMD_ERASE_VERIFY = 0xA0, - CMD_PROGRAM = 0x40, - CMD_PROGRAM_VERIFY = 0xC0, - CMD_RESET = 0xFF + CMD_SET_READ = 0x00, + CMD_READ_AUTO_SELECT = 0x80, + CMD_READ_SIGNATURE = 0x90, + CMD_ERASE = 0x20, + CMD_ERASE_CONFIRM = 0x20, + CMD_ERASE_VERIFY = 0xA0, + CMD_PROGRAM = 0x40, + CMD_PROGRAM_VERIFY = 0xC0, + CMD_RESET = 0xFF }; typedef struct flash_t { uint8_t command; + uint8_t is_amd; uint8_t pad; uint8_t pad0; - uint8_t pad1; uint8_t *array; mem_mapping_t mapping; @@ -83,11 +85,22 @@ flash_read(uint32_t addr, void *priv) ret = dev->array[addr]; break; + case CMD_READ_AUTO_SELECT: + if (!dev->is_amd) + break; + fallthrough; case CMD_READ_SIGNATURE: - if (addr == 0x00000) - ret = 0x31; /* CATALYST */ - else if (addr == 0x00001) - ret = 0xB4; /* 28F010 */ + if (dev->is_amd) { + if (addr == 0x00000) + ret = 0x01; /* AMD */ + else if (addr == 0x00001) + ret = 0xa7; /* Am28F010 */ + } else { + if (addr == 0x00000) + ret = 0x31; /* CATALYST */ + else if (addr == 0x00001) + ret = 0xb4; /* 28F010 */ + } break; default: @@ -205,6 +218,7 @@ catalyst_flash_init(UNUSED(const device_t *info)) catalyst_flash_add_mappings(dev); dev->command = CMD_RESET; + dev->is_amd = info->local; fp = nvr_fopen(flash_path, "rb"); if (fp) { @@ -244,3 +258,17 @@ const device_t catalyst_flash_device = { .force_redraw = NULL, .config = NULL }; + +const device_t amd_am28f010_flash_device = { + .name = "AMD Am28F010-D Flash BIOS", + .internal_name = "amd_am28f010_flash", + .flags = DEVICE_PCI, + .local = 1, + .init = catalyst_flash_init, + .close = catalyst_flash_close, + .reset = catalyst_flash_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 5be854154..6b3a26739 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -197,6 +197,49 @@ add_library(ui STATIC qt_mediahistorymanager.cpp qt_mediahistorymanager.hpp + qt_updatecheck.cpp + qt_updatecheck.hpp + qt_updatecheckdialog.cpp + qt_updatecheckdialog.hpp + qt_updatecheckdialog.ui + qt_updatedetails.cpp + qt_updatedetails.hpp + qt_updatedetails.ui + qt_downloader.cpp + qt_downloader.hpp + + qt_vmmanager_clientsocket.cpp + qt_vmmanager_clientsocket.hpp + qt_vmmanager_serversocket.cpp + qt_vmmanager_serversocket.hpp + qt_vmmanager_protocol.cpp + qt_vmmanager_protocol.hpp + qt_vmmanager_details.hpp + qt_vmmanager_details.cpp + qt_vmmanager_details.ui + qt_vmmanager_addmachine.cpp + qt_vmmanager_addmachine.hpp + qt_vmmanager_detailsection.cpp + qt_vmmanager_detailsection.hpp + qt_vmmanager_detailsection.ui + qt_vmmanager_listviewdelegate.hpp + qt_vmmanager_listviewdelegate.cpp + qt_vmmanager_preferences.cpp + qt_vmmanager_preferences.hpp + qt_vmmanager_preferences.ui + qt_vmmanager_main.hpp + qt_vmmanager_main.cpp + qt_vmmanager_main.ui + qt_vmmanager_model.cpp + qt_vmmanager_model.hpp + qt_vmmanager_system.cpp + qt_vmmanager_system.hpp + qt_vmmanager_config.cpp + qt_vmmanager_config.hpp + qt_vmmanager_mainwindow.cpp + qt_vmmanager_mainwindow.hpp + qt_vmmanager_mainwindow.ui + ../qt_resources.qrc ./qdarkstyle/dark/darkstyle.qrc diff --git a/src/qt/assets/86box-wizard.png b/src/qt/assets/86box-wizard.png new file mode 100644 index 000000000..19ecda8c7 Binary files /dev/null and b/src/qt/assets/86box-wizard.png differ diff --git a/src/qt/assets/systemicons/cpq_deskpro.png b/src/qt/assets/systemicons/cpq_deskpro.png new file mode 100644 index 000000000..1bbca68a3 Binary files /dev/null and b/src/qt/assets/systemicons/cpq_deskpro.png differ diff --git a/src/qt/assets/systemicons/cpq_port_386.png b/src/qt/assets/systemicons/cpq_port_386.png new file mode 100644 index 000000000..4c55b3559 Binary files /dev/null and b/src/qt/assets/systemicons/cpq_port_386.png differ diff --git a/src/qt/assets/systemicons/cpq_port_II.png b/src/qt/assets/systemicons/cpq_port_II.png new file mode 100644 index 000000000..3254d9b5e Binary files /dev/null and b/src/qt/assets/systemicons/cpq_port_II.png differ diff --git a/src/qt/assets/systemicons/cpq_port_III.png b/src/qt/assets/systemicons/cpq_port_III.png new file mode 100644 index 000000000..65d2f714e Binary files /dev/null and b/src/qt/assets/systemicons/cpq_port_III.png differ diff --git a/src/qt/assets/systemicons/cpq_portable.png b/src/qt/assets/systemicons/cpq_portable.png new file mode 100644 index 000000000..d3dc381e4 Binary files /dev/null and b/src/qt/assets/systemicons/cpq_portable.png differ diff --git a/src/qt/assets/systemicons/cpq_pres_2240.png b/src/qt/assets/systemicons/cpq_pres_2240.png new file mode 100644 index 000000000..c50043cdd Binary files /dev/null and b/src/qt/assets/systemicons/cpq_pres_2240.png differ diff --git a/src/qt/assets/systemicons/cpq_pres_4500.png b/src/qt/assets/systemicons/cpq_pres_4500.png new file mode 100644 index 000000000..edd955b5a Binary files /dev/null and b/src/qt/assets/systemicons/cpq_pres_4500.png differ diff --git a/src/qt/assets/systemicons/ibm330.png b/src/qt/assets/systemicons/ibm330.png new file mode 100644 index 000000000..90637dc4c Binary files /dev/null and b/src/qt/assets/systemicons/ibm330.png differ diff --git a/src/qt/assets/systemicons/ibm_at.png b/src/qt/assets/systemicons/ibm_at.png new file mode 100644 index 000000000..e6710180e Binary files /dev/null and b/src/qt/assets/systemicons/ibm_at.png differ diff --git a/src/qt/assets/systemicons/ibm_pc_81.png b/src/qt/assets/systemicons/ibm_pc_81.png new file mode 100644 index 000000000..4f398d468 Binary files /dev/null and b/src/qt/assets/systemicons/ibm_pc_81.png differ diff --git a/src/qt/assets/systemicons/ibm_pc_82.png b/src/qt/assets/systemicons/ibm_pc_82.png new file mode 100644 index 000000000..4f398d468 Binary files /dev/null and b/src/qt/assets/systemicons/ibm_pc_82.png differ diff --git a/src/qt/assets/systemicons/ibm_pcjr.png b/src/qt/assets/systemicons/ibm_pcjr.png new file mode 100644 index 000000000..1f3014bb4 Binary files /dev/null and b/src/qt/assets/systemicons/ibm_pcjr.png differ diff --git a/src/qt/assets/systemicons/ibm_ps2_m70.png b/src/qt/assets/systemicons/ibm_ps2_m70.png new file mode 100644 index 000000000..af433ebb3 Binary files /dev/null and b/src/qt/assets/systemicons/ibm_ps2_m70.png differ diff --git a/src/qt/assets/systemicons/ibm_ps2_m80.png b/src/qt/assets/systemicons/ibm_ps2_m80.png new file mode 100644 index 000000000..9df02adff Binary files /dev/null and b/src/qt/assets/systemicons/ibm_ps2_m80.png differ diff --git a/src/qt/assets/systemicons/ibm_psvp_486.png b/src/qt/assets/systemicons/ibm_psvp_486.png new file mode 100644 index 000000000..af5a95675 Binary files /dev/null and b/src/qt/assets/systemicons/ibm_psvp_486.png differ diff --git a/src/qt/assets/systemicons/ibm_psvp_p60.png b/src/qt/assets/systemicons/ibm_psvp_p60.png new file mode 100644 index 000000000..af5a95675 Binary files /dev/null and b/src/qt/assets/systemicons/ibm_psvp_p60.png differ diff --git a/src/qt/assets/systemicons/ibm_xt_82.png b/src/qt/assets/systemicons/ibm_xt_82.png new file mode 100644 index 000000000..4f398d468 Binary files /dev/null and b/src/qt/assets/systemicons/ibm_xt_82.png differ diff --git a/src/qt/assets/systemicons/ibm_xt_86.png b/src/qt/assets/systemicons/ibm_xt_86.png new file mode 100644 index 000000000..4f398d468 Binary files /dev/null and b/src/qt/assets/systemicons/ibm_xt_86.png differ diff --git a/src/qt/assets/systemicons/olivetti_m19.png b/src/qt/assets/systemicons/olivetti_m19.png new file mode 100644 index 000000000..766e335f7 Binary files /dev/null and b/src/qt/assets/systemicons/olivetti_m19.png differ diff --git a/src/qt/assets/systemicons/olivetti_m21.png b/src/qt/assets/systemicons/olivetti_m21.png new file mode 100644 index 000000000..5e0ee4b52 Binary files /dev/null and b/src/qt/assets/systemicons/olivetti_m21.png differ diff --git a/src/qt/assets/systemicons/olivetti_m24.png b/src/qt/assets/systemicons/olivetti_m24.png new file mode 100644 index 000000000..e48356c32 Binary files /dev/null and b/src/qt/assets/systemicons/olivetti_m24.png differ diff --git a/src/qt/assets/systemicons/olivetti_m24sp.png b/src/qt/assets/systemicons/olivetti_m24sp.png new file mode 100644 index 000000000..e48356c32 Binary files /dev/null and b/src/qt/assets/systemicons/olivetti_m24sp.png differ diff --git a/src/qt/assets/systemicons/os_archlinux_x2.png b/src/qt/assets/systemicons/os_archlinux_x2.png new file mode 100644 index 000000000..1b218a76f Binary files /dev/null and b/src/qt/assets/systemicons/os_archlinux_x2.png differ diff --git a/src/qt/assets/systemicons/os_cloud_x2.png b/src/qt/assets/systemicons/os_cloud_x2.png new file mode 100644 index 000000000..9bd42f9ac Binary files /dev/null and b/src/qt/assets/systemicons/os_cloud_x2.png differ diff --git a/src/qt/assets/systemicons/os_debian_x2.png b/src/qt/assets/systemicons/os_debian_x2.png new file mode 100644 index 000000000..a6644c33d Binary files /dev/null and b/src/qt/assets/systemicons/os_debian_x2.png differ diff --git a/src/qt/assets/systemicons/os_dos_x2.png b/src/qt/assets/systemicons/os_dos_x2.png new file mode 100644 index 000000000..b6df56ef5 Binary files /dev/null and b/src/qt/assets/systemicons/os_dos_x2.png differ diff --git a/src/qt/assets/systemicons/os_fedora_x2.png b/src/qt/assets/systemicons/os_fedora_x2.png new file mode 100644 index 000000000..120d247a8 Binary files /dev/null and b/src/qt/assets/systemicons/os_fedora_x2.png differ diff --git a/src/qt/assets/systemicons/os_freebsd_x2.png b/src/qt/assets/systemicons/os_freebsd_x2.png new file mode 100644 index 000000000..dd6f88d41 Binary files /dev/null and b/src/qt/assets/systemicons/os_freebsd_x2.png differ diff --git a/src/qt/assets/systemicons/os_gentoo_x2.png b/src/qt/assets/systemicons/os_gentoo_x2.png new file mode 100644 index 000000000..f27afa5fc Binary files /dev/null and b/src/qt/assets/systemicons/os_gentoo_x2.png differ diff --git a/src/qt/assets/systemicons/os_jrockitve_x2.png b/src/qt/assets/systemicons/os_jrockitve_x2.png new file mode 100644 index 000000000..4283cad5e Binary files /dev/null and b/src/qt/assets/systemicons/os_jrockitve_x2.png differ diff --git a/src/qt/assets/systemicons/os_l4_x2.png b/src/qt/assets/systemicons/os_l4_x2.png new file mode 100644 index 000000000..9fbbaa183 Binary files /dev/null and b/src/qt/assets/systemicons/os_l4_x2.png differ diff --git a/src/qt/assets/systemicons/os_linux22_x2.png b/src/qt/assets/systemicons/os_linux22_x2.png new file mode 100644 index 000000000..0de56653a Binary files /dev/null and b/src/qt/assets/systemicons/os_linux22_x2.png differ diff --git a/src/qt/assets/systemicons/os_linux24_x2.png b/src/qt/assets/systemicons/os_linux24_x2.png new file mode 100644 index 000000000..b3df83b7f Binary files /dev/null and b/src/qt/assets/systemicons/os_linux24_x2.png differ diff --git a/src/qt/assets/systemicons/os_linux26_x2.png b/src/qt/assets/systemicons/os_linux26_x2.png new file mode 100644 index 000000000..8fdf52df7 Binary files /dev/null and b/src/qt/assets/systemicons/os_linux26_x2.png differ diff --git a/src/qt/assets/systemicons/os_linux_x2.png b/src/qt/assets/systemicons/os_linux_x2.png new file mode 100644 index 000000000..d4c2eeebe Binary files /dev/null and b/src/qt/assets/systemicons/os_linux_x2.png differ diff --git a/src/qt/assets/systemicons/os_macosx_x2.png b/src/qt/assets/systemicons/os_macosx_x2.png new file mode 100644 index 000000000..38eb2e5a7 Binary files /dev/null and b/src/qt/assets/systemicons/os_macosx_x2.png differ diff --git a/src/qt/assets/systemicons/os_mandriva_x2.png b/src/qt/assets/systemicons/os_mandriva_x2.png new file mode 100644 index 000000000..a09e9c170 Binary files /dev/null and b/src/qt/assets/systemicons/os_mandriva_x2.png differ diff --git a/src/qt/assets/systemicons/os_netbsd_x2.png b/src/qt/assets/systemicons/os_netbsd_x2.png new file mode 100644 index 000000000..9fa38a7a6 Binary files /dev/null and b/src/qt/assets/systemicons/os_netbsd_x2.png differ diff --git a/src/qt/assets/systemicons/os_netware_x2.png b/src/qt/assets/systemicons/os_netware_x2.png new file mode 100644 index 000000000..4bcc96521 Binary files /dev/null and b/src/qt/assets/systemicons/os_netware_x2.png differ diff --git a/src/qt/assets/systemicons/os_openbsd_x2.png b/src/qt/assets/systemicons/os_openbsd_x2.png new file mode 100644 index 000000000..13ae3a0db Binary files /dev/null and b/src/qt/assets/systemicons/os_openbsd_x2.png differ diff --git a/src/qt/assets/systemicons/os_opensuse_x2.png b/src/qt/assets/systemicons/os_opensuse_x2.png new file mode 100644 index 000000000..4d1696d9b Binary files /dev/null and b/src/qt/assets/systemicons/os_opensuse_x2.png differ diff --git a/src/qt/assets/systemicons/os_oracle_x2.png b/src/qt/assets/systemicons/os_oracle_x2.png new file mode 100644 index 000000000..545e885cb Binary files /dev/null and b/src/qt/assets/systemicons/os_oracle_x2.png differ diff --git a/src/qt/assets/systemicons/os_oraclesolaris_x2.png b/src/qt/assets/systemicons/os_oraclesolaris_x2.png new file mode 100644 index 000000000..8db66abe3 Binary files /dev/null and b/src/qt/assets/systemicons/os_oraclesolaris_x2.png differ diff --git a/src/qt/assets/systemicons/os_os2_other_x2.png b/src/qt/assets/systemicons/os_os2_other_x2.png new file mode 100644 index 000000000..2d37846a0 Binary files /dev/null and b/src/qt/assets/systemicons/os_os2_other_x2.png differ diff --git a/src/qt/assets/systemicons/os_os2ecs_x2.png b/src/qt/assets/systemicons/os_os2ecs_x2.png new file mode 100644 index 000000000..261f9f56c Binary files /dev/null and b/src/qt/assets/systemicons/os_os2ecs_x2.png differ diff --git a/src/qt/assets/systemicons/os_os2warp3_x2.png b/src/qt/assets/systemicons/os_os2warp3_x2.png new file mode 100644 index 000000000..1be5a696c Binary files /dev/null and b/src/qt/assets/systemicons/os_os2warp3_x2.png differ diff --git a/src/qt/assets/systemicons/os_os2warp45_x2.png b/src/qt/assets/systemicons/os_os2warp45_x2.png new file mode 100644 index 000000000..d1a4df0c2 Binary files /dev/null and b/src/qt/assets/systemicons/os_os2warp45_x2.png differ diff --git a/src/qt/assets/systemicons/os_os2warp4_x2.png b/src/qt/assets/systemicons/os_os2warp4_x2.png new file mode 100644 index 000000000..0a81c8759 Binary files /dev/null and b/src/qt/assets/systemicons/os_os2warp4_x2.png differ diff --git a/src/qt/assets/systemicons/os_other_x2.png b/src/qt/assets/systemicons/os_other_x2.png new file mode 100644 index 000000000..9602353c0 Binary files /dev/null and b/src/qt/assets/systemicons/os_other_x2.png differ diff --git a/src/qt/assets/systemicons/os_qnx_x2.png b/src/qt/assets/systemicons/os_qnx_x2.png new file mode 100644 index 000000000..b124cfa6e Binary files /dev/null and b/src/qt/assets/systemicons/os_qnx_x2.png differ diff --git a/src/qt/assets/systemicons/os_redhat_x2.png b/src/qt/assets/systemicons/os_redhat_x2.png new file mode 100644 index 000000000..a756e8aac Binary files /dev/null and b/src/qt/assets/systemicons/os_redhat_x2.png differ diff --git a/src/qt/assets/systemicons/os_solaris_x2.png b/src/qt/assets/systemicons/os_solaris_x2.png new file mode 100644 index 000000000..2dfd2ac74 Binary files /dev/null and b/src/qt/assets/systemicons/os_solaris_x2.png differ diff --git a/src/qt/assets/systemicons/os_turbolinux_x2.png b/src/qt/assets/systemicons/os_turbolinux_x2.png new file mode 100644 index 000000000..4d5ee4ab1 Binary files /dev/null and b/src/qt/assets/systemicons/os_turbolinux_x2.png differ diff --git a/src/qt/assets/systemicons/os_ubuntu_x2.png b/src/qt/assets/systemicons/os_ubuntu_x2.png new file mode 100644 index 000000000..9b6302b37 Binary files /dev/null and b/src/qt/assets/systemicons/os_ubuntu_x2.png differ diff --git a/src/qt/assets/systemicons/os_win10_x2.png b/src/qt/assets/systemicons/os_win10_x2.png new file mode 100644 index 000000000..1d6e81392 Binary files /dev/null and b/src/qt/assets/systemicons/os_win10_x2.png differ diff --git a/src/qt/assets/systemicons/os_win2k3_x2.png b/src/qt/assets/systemicons/os_win2k3_x2.png new file mode 100644 index 000000000..45bec005d Binary files /dev/null and b/src/qt/assets/systemicons/os_win2k3_x2.png differ diff --git a/src/qt/assets/systemicons/os_win2k8_x2.png b/src/qt/assets/systemicons/os_win2k8_x2.png new file mode 100644 index 000000000..d97a2789d Binary files /dev/null and b/src/qt/assets/systemicons/os_win2k8_x2.png differ diff --git a/src/qt/assets/systemicons/os_win2k_x2.png b/src/qt/assets/systemicons/os_win2k_x2.png new file mode 100644 index 000000000..a773288ed Binary files /dev/null and b/src/qt/assets/systemicons/os_win2k_x2.png differ diff --git a/src/qt/assets/systemicons/os_win31_x2.png b/src/qt/assets/systemicons/os_win31_x2.png new file mode 100644 index 000000000..5ca2005d6 Binary files /dev/null and b/src/qt/assets/systemicons/os_win31_x2.png differ diff --git a/src/qt/assets/systemicons/os_win7_x2.png b/src/qt/assets/systemicons/os_win7_x2.png new file mode 100644 index 000000000..c8ce57a2b Binary files /dev/null and b/src/qt/assets/systemicons/os_win7_x2.png differ diff --git a/src/qt/assets/systemicons/os_win81_x2.png b/src/qt/assets/systemicons/os_win81_x2.png new file mode 100644 index 000000000..07131ed6c Binary files /dev/null and b/src/qt/assets/systemicons/os_win81_x2.png differ diff --git a/src/qt/assets/systemicons/os_win8_x2.png b/src/qt/assets/systemicons/os_win8_x2.png new file mode 100644 index 000000000..ff94c2dd1 Binary files /dev/null and b/src/qt/assets/systemicons/os_win8_x2.png differ diff --git a/src/qt/assets/systemicons/os_win95_x2.png b/src/qt/assets/systemicons/os_win95_x2.png new file mode 100644 index 000000000..efd62799e Binary files /dev/null and b/src/qt/assets/systemicons/os_win95_x2.png differ diff --git a/src/qt/assets/systemicons/os_win98_x2.png b/src/qt/assets/systemicons/os_win98_x2.png new file mode 100644 index 000000000..c8fa4e7bb Binary files /dev/null and b/src/qt/assets/systemicons/os_win98_x2.png differ diff --git a/src/qt/assets/systemicons/os_win_other_x2.png b/src/qt/assets/systemicons/os_win_other_x2.png new file mode 100644 index 000000000..fac95889f Binary files /dev/null and b/src/qt/assets/systemicons/os_win_other_x2.png differ diff --git a/src/qt/assets/systemicons/os_winme_x2.png b/src/qt/assets/systemicons/os_winme_x2.png new file mode 100644 index 000000000..1c268c84b Binary files /dev/null and b/src/qt/assets/systemicons/os_winme_x2.png differ diff --git a/src/qt/assets/systemicons/os_winnt4_x2.png b/src/qt/assets/systemicons/os_winnt4_x2.png new file mode 100644 index 000000000..c3352abcd Binary files /dev/null and b/src/qt/assets/systemicons/os_winnt4_x2.png differ diff --git a/src/qt/assets/systemicons/os_winvista_x2.png b/src/qt/assets/systemicons/os_winvista_x2.png new file mode 100644 index 000000000..7b633b79f Binary files /dev/null and b/src/qt/assets/systemicons/os_winvista_x2.png differ diff --git a/src/qt/assets/systemicons/os_winxp_x2.png b/src/qt/assets/systemicons/os_winxp_x2.png new file mode 100644 index 000000000..b97e6b51d Binary files /dev/null and b/src/qt/assets/systemicons/os_winxp_x2.png differ diff --git a/src/qt/assets/systemicons/os_xandros_x2.png b/src/qt/assets/systemicons/os_xandros_x2.png new file mode 100644 index 000000000..23de5ca91 Binary files /dev/null and b/src/qt/assets/systemicons/os_xandros_x2.png differ diff --git a/src/qt/assets/systemicons/pb_bora_pro.png b/src/qt/assets/systemicons/pb_bora_pro.png new file mode 100644 index 000000000..6aaaf9d26 Binary files /dev/null and b/src/qt/assets/systemicons/pb_bora_pro.png differ diff --git a/src/qt/assets/systemicons/pb_pb410.png b/src/qt/assets/systemicons/pb_pb410.png new file mode 100644 index 000000000..c78c0496b Binary files /dev/null and b/src/qt/assets/systemicons/pb_pb410.png differ diff --git a/src/qt/assets/systemicons/pb_pb640.png b/src/qt/assets/systemicons/pb_pb640.png new file mode 100644 index 000000000..d0be550f1 Binary files /dev/null and b/src/qt/assets/systemicons/pb_pb640.png differ diff --git a/src/qt/assets/systemicons/pb_pb680.png b/src/qt/assets/systemicons/pb_pb680.png new file mode 100644 index 000000000..a697d5dd0 Binary files /dev/null and b/src/qt/assets/systemicons/pb_pb680.png differ diff --git a/src/qt/assets/systemicons/tandy_1000.png b/src/qt/assets/systemicons/tandy_1000.png new file mode 100644 index 000000000..b50f2c1e6 Binary files /dev/null and b/src/qt/assets/systemicons/tandy_1000.png differ diff --git a/src/qt/assets/systemicons/tandy_1000_hx.png b/src/qt/assets/systemicons/tandy_1000_hx.png new file mode 100644 index 000000000..b770a6b7c Binary files /dev/null and b/src/qt/assets/systemicons/tandy_1000_hx.png differ diff --git a/src/qt/assets/systemicons/tandy_1000_sl2.png b/src/qt/assets/systemicons/tandy_1000_sl2.png new file mode 100644 index 000000000..b7feae92a Binary files /dev/null and b/src/qt/assets/systemicons/tandy_1000_sl2.png differ diff --git a/src/qt/assets/systemicons/toshiba_t1000.png b/src/qt/assets/systemicons/toshiba_t1000.png new file mode 100644 index 000000000..a2dbfc382 Binary files /dev/null and b/src/qt/assets/systemicons/toshiba_t1000.png differ diff --git a/src/qt/assets/systemicons/toshiba_t1200.png b/src/qt/assets/systemicons/toshiba_t1200.png new file mode 100644 index 000000000..8c3cf0c37 Binary files /dev/null and b/src/qt/assets/systemicons/toshiba_t1200.png differ diff --git a/src/qt/assets/systemicons/toshiba_t1200_hdd.png b/src/qt/assets/systemicons/toshiba_t1200_hdd.png new file mode 100644 index 000000000..8c3cf0c37 Binary files /dev/null and b/src/qt/assets/systemicons/toshiba_t1200_hdd.png differ diff --git a/src/qt/icons/green-square-16.png b/src/qt/icons/green-square-16.png new file mode 100644 index 000000000..cb42c38eb Binary files /dev/null and b/src/qt/icons/green-square-16.png differ diff --git a/src/qt/icons/pause-16.png b/src/qt/icons/pause-16.png new file mode 100644 index 000000000..375780232 Binary files /dev/null and b/src/qt/icons/pause-16.png differ diff --git a/src/qt/icons/play-16.png b/src/qt/icons/play-16.png new file mode 100644 index 000000000..bde40f503 Binary files /dev/null and b/src/qt/icons/play-16.png differ diff --git a/src/qt/icons/red-power-16.png b/src/qt/icons/red-power-16.png new file mode 100644 index 000000000..c90ef491f Binary files /dev/null and b/src/qt/icons/red-power-16.png differ diff --git a/src/qt/icons/red-square-16.png b/src/qt/icons/red-square-16.png new file mode 100644 index 000000000..32faa7cdc Binary files /dev/null and b/src/qt/icons/red-square-16.png differ diff --git a/src/qt/icons/stop-16.png b/src/qt/icons/stop-16.png new file mode 100644 index 000000000..d73cad140 Binary files /dev/null and b/src/qt/icons/stop-16.png differ diff --git a/src/qt/icons/yellow-square-16.png b/src/qt/icons/yellow-square-16.png new file mode 100644 index 000000000..197cf394e Binary files /dev/null and b/src/qt/icons/yellow-square-16.png differ diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 19975c2c9..bb8a9caf5 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -598,7 +598,10 @@ msgid "ISA RTC:" msgstr "ISA RTC:" msgid "ISA Memory Expansion" -msgstr "Карта расширения памяти ISA" +msgstr "Карты расширения памяти ISA" + +msgid "ISA ROM Cards" +msgstr "Карты ПЗУ ISA" msgid "Card 1:" msgstr "Карта 1:" @@ -1237,7 +1240,7 @@ msgid "Pen" msgstr "Ручка" msgid "Host CD/DVD Drive (%1:)" -msgstr "CD/DVD-привод хоста (%1:)" +msgstr "CD/DVD Привод хоста (%1:)" msgid "&Connected" msgstr "&Кабель подключен" @@ -1249,7 +1252,7 @@ msgid "Create..." msgstr "Создать..." msgid "Host CD/DVD Drive (%1)" -msgstr "CD/DVD-привод хоста (%1)" +msgstr "CD/DVD Привод хоста (%1)" msgid "Unknown Bus" msgstr "Неизвестная шина" @@ -1413,12 +1416,54 @@ msgstr "Системный MIDI" msgid "MIDI Input Device" msgstr "Устройство ввода MIDI" +msgid "BIOS file" +msgstr "Файл BIOS" + +msgid "BIOS file (ROM #1)" +msgstr "Файл BIOS (ПЗУ #1)" + +msgid "BIOS file (ROM #2)" +msgstr "Файл BIOS (ПЗУ #2)" + +msgid "BIOS file (ROM #3)" +msgstr "Файл BIOS (ПЗУ #3)" + +msgid "BIOS file (ROM #4)" +msgstr "Файл BIOS (ПЗУ #4)" + msgid "BIOS Address" msgstr "Адрес BIOS" +msgid "BIOS address (ROM #1)" +msgstr "Адрес BIOS (ПЗУ #1)" + +msgid "BIOS address (ROM #2)" +msgstr "Адрес BIOS (ПЗУ #2)" + +msgid "BIOS address (ROM #3)" +msgstr "Адрес BIOS (ПЗУ #3)" + +msgid "BIOS address (ROM #4)" +msgstr "Адрес BIOS (ПЗУ #4)" + msgid "Enable BIOS extension ROM Writes" msgstr "Разрешить запись в ПЗУ расширения BIOS" +msgid "Enable BIOS extension ROM Writes (ROM #1)" +msgstr "Разрешить запись в ПЗУ расширения BIOS (ПЗУ #1)" + +msgid "Enable BIOS extension ROM Writes (ROM #2)" +msgstr "Разрешить запись в ПЗУ расширения BIOS (ПЗУ #2)" + +msgid "Enable BIOS extension ROM Writes (ROM #3)" +msgstr "Разрешить запись в ПЗУ расширения BIOS (ПЗУ #3)" + +msgid "Enable BIOS extension ROM Writes (ROM #4)" +msgstr "Разрешить запись в ПЗУ расширения BIOS (ПЗУ #4)" + +msgid "Linear framebuffer base" +msgstr "Линейная база кадрового буфера" + msgid "Address" msgstr "Адрес" @@ -1428,6 +1473,21 @@ msgstr "IRQ" msgid "BIOS Revision" msgstr "Версия BIOS" +msgid "BIOS Version" +msgstr "Версия BIOS" + +msgid "BIOS Versions" +msgstr "Версии BIOS" + +msgid "BIOS Language" +msgstr "Язык BIOS" + +msgid "IBM 5161 Expansion Unit" +msgstr "Блок расширения IBM 5161" + +msgid "IBM Cassette Basic" +msgstr "Кассетный бейсик IBM" + msgid "Translate 26 -> 17" msgstr "Переводить 26 -> 17" @@ -1443,6 +1503,18 @@ msgstr "Инвертировать цвета" msgid "BIOS size" msgstr "Размер BIOS" +msgid "BIOS size (ROM #1)" +msgstr "Размер BIOS (ПЗУ #1)" + +msgid "BIOS size (ROM #2)" +msgstr "Размер BIOS (ПЗУ #2)" + +msgid "BIOS size (ROM #3)" +msgstr "Размер BIOS (ПЗУ #3)" + +msgid "BIOS size (ROM #4)" +msgstr "Размер BIOS (ПЗУ #4)" + msgid "Map C0000-C7FFF as UMB" msgstr "Отображение C0000-C7FFF в качестве UMB" @@ -1518,6 +1590,9 @@ msgstr "Уровень реверберации" msgid "Interpolation Method" msgstr "Метод интерполяции" +msgid "Dynamic Sample Loading" +msgstr "Динамическая загрузка сэмплов" + msgid "Reverb Output Gain" msgstr "Усиление выходного сигнала ревербератора" @@ -1606,7 +1681,7 @@ msgid "Enable Game port" msgstr "Включить игровой порт" msgid "Surround module" -msgstr "Модуль объемного звучания" +msgstr "Модуль объёмного звучания" msgid "CODEC" msgstr "Кодек" @@ -1617,6 +1692,9 @@ msgstr "Поднимать прерывание кодека при настро msgid "SB Address" msgstr "Адрес SB" +msgid "Use EEPROM setting" +msgstr "Использовать настройку EEPROM" + msgid "WSS IRQ" msgstr "IRQ WSS" @@ -1701,6 +1779,9 @@ msgstr "Тип RAMDAC" msgid "Blend" msgstr "Смесь" +msgid "Font" +msgstr "Шрифт" + msgid "Bilinear filtering" msgstr "Билинейная фильтрация" @@ -1746,6 +1827,33 @@ msgstr "Скорость передачи данных" msgid "EMS mode" msgstr "Режим EMS" +msgid "EMS Address" +msgstr "Адрес EMS" + +msgid "EMS 1 Address" +msgstr "Адрес EMS 1" + +msgid "EMS 2 Address" +msgstr "Адрес EMS 2" + +msgid "EMS Memory Size" +msgstr "Размер памяти EMS" + +msgid "EMS 1 Memory Size" +msgstr "Размер памяти EMS 1" + +msgid "EMS 2 Memory Size" +msgstr "Размер памяти EMS 2" + +msgid "Enable EMS" +msgstr "Включить EMS" + +msgid "Enable EMS 1" +msgstr "Включить EMS 1" + +msgid "Enable EMS 2" +msgstr "Включить EMS 2" + msgid "Address for > 2 MB" msgstr "Адрес для > 2 МБ" @@ -1765,10 +1873,10 @@ msgid "BIOS setting + Hotkeys (off during POST)" msgstr "Настройка BIOS + горячие клавиши (отключается во время POST)" msgid "64 kB starting from F0000" -msgstr "64 кБ, начиная с F0000" +msgstr "64 КБ, начиная с F0000" msgid "128 kB starting from E0000 (address MSB inverted, last 64KB first)" -msgstr "128 кБ, начиная с E0000 (адрес MSB инвертирован, сначала последние 64 КБ)" +msgstr "128 КБ, начиная с E0000 (адрес MSB инвертирован, сначала последние 64 КБ)" msgid "Sine" msgstr "Синусоидальная" @@ -1792,7 +1900,7 @@ msgid "45 Hz (JMP2 not populated)" msgstr "45 Гц (без джампера на JMP2)" msgid "Two" -msgstr "Два" +msgstr "Две" msgid "Three" msgstr "Три" @@ -1935,6 +2043,9 @@ msgstr "Янтарный" msgid "Gray" msgstr "Серый" +msgid "Grayscale" +msgstr "Монохромный" + msgid "Color" msgstr "Цветной" @@ -1950,6 +2061,12 @@ msgstr "Другие языки" msgid "Bochs latest" msgstr "Bochs последний" +msgid "Apply overscan deltas" +msgstr "Применить дельты вылетов развёртки" + +msgid "Mono Interlaced" +msgstr "Монохромный с чересстрочной развёрткой" + msgid "Mono Non-Interlaced" msgstr "Монохромный без чересстрочной развёртки" @@ -2095,7 +2212,7 @@ msgid "TrueType fonts in the \"roms/printer/fonts\" directory are required for t msgstr "Шрифты TrueType в каталоге \"roms/printer/fonts\" необходимы для эмуляции стандартного матричного принтера ESC/P." msgid "Inhibit multimedia keys" -msgstr "Перехватывать мультимедиа-клавиши" +msgstr "Перехватывать мультимедийные клавиши" msgid "Ask for confirmation before saving settings" msgstr "Запрашивать подтверждение перед сохранением настроек" @@ -2182,7 +2299,7 @@ msgid "Send Control+Alt+Escape" msgstr "Отправить Control+Alt+Escape" msgid "Toggle fullscreen" -msgstr "Переключить на полноэкранный режим" +msgstr "Переключить полноэкранный режим" msgid "Screenshot" msgstr "Скриншот" diff --git a/src/qt/qt_downloader.cpp b/src/qt/qt_downloader.cpp new file mode 100644 index 000000000..329aeeafb --- /dev/null +++ b/src/qt/qt_downloader.cpp @@ -0,0 +1,95 @@ +/* + * 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. + * + * Downloader module + * + * + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ + +#include +#include +#include +#include + +#include "qt_downloader.hpp" + +extern "C" { +#include <86box/plat.h> +} + +Downloader:: +Downloader(const DownloadLocation downloadLocation, QObject *parent) + : QObject(parent) + , file(nullptr) + , reply(nullptr) + , variantData(QVariant::Invalid) +{ + char PATHBUF[256]; + switch (downloadLocation) { + case DownloadLocation::Data: + plat_get_global_data_dir(PATHBUF, 255); + break; + case DownloadLocation::Config: + plat_get_global_config_dir(PATHBUF, 255); + break; + case DownloadLocation::Temp: + plat_get_temp_dir(PATHBUF, 255); + break; + } + downloadDirectory = QDir(PATHBUF); +} + +Downloader::~Downloader() { delete file; } + +void Downloader::download(const QUrl &url, const QString &filepath, const QVariant &varData) { + + variantData = varData; + // temporary until I get the plat stuff fixed + // const auto global_dir = temporaryGetGlobalDataDir(); + // qDebug() << "I was passed filepath " << filepath; + // Join with filename to create final file + // const auto final_path = QDir(global_dir).filePath(filepath); + const auto final_path = downloadDirectory.filePath(filepath); + + file = new QFile(final_path); + if(!file->open(QIODevice::WriteOnly)) { + qWarning() << "Unable to open file " << final_path; + return; + } + + const auto nam = new QNetworkAccessManager(this); + // Create the network request and execute + const auto request = QNetworkRequest(url); + reply = nam->get(request); + // Connect to the finished signal + connect(reply, &QNetworkReply::finished, this, &Downloader::onResult); +} + +void +Downloader::onResult() +{ + if (reply->error()) { + qWarning() << "Error returned from QNetworkRequest: " << reply->errorString(); + emit errorOccurred(reply->errorString()); + reply->deleteLater(); + return; + } + + file->write(reply->readAll()); + file->flush(); + file->close(); + + reply->deleteLater(); + qDebug() << Q_FUNC_INFO << "Downloaded complete: file written to " << file->fileName(); + emit downloadCompleted(file->fileName(), variantData); +} + diff --git a/src/qt/qt_downloader.hpp b/src/qt/qt_downloader.hpp new file mode 100644 index 000000000..0bd3f1fee --- /dev/null +++ b/src/qt/qt_downloader.hpp @@ -0,0 +1,57 @@ +/* + * 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. + * + * Header for the downloader module + * + * + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ + +#ifndef QT_DOWNLOADER_HPP +#define QT_DOWNLOADER_HPP + +#include +#include +#include +#include + + +class Downloader : public QObject { + Q_OBJECT +public: + enum class DownloadLocation { + Data, // AppDataLocation via plat_get_global_data_dir() + Config, // AppConfigLocation via plat_get_global_config_dir() + Temp // TempLocation via plat_get_temp_dir() + }; + explicit Downloader(DownloadLocation downloadLocation = DownloadLocation::Data, QObject *parent = nullptr); + ~Downloader() final; + + void download(const QUrl &url, const QString &filepath, const QVariant &varData = QVariant::Invalid); + +signals: + // Signal emitted when the download is successful + void downloadCompleted(QString filename, QVariant varData); + // Signal emitted when an error occurs + void errorOccurred(const QString&); + +private slots: + void onResult(); + +private: + QFile *file; + QNetworkAccessManager nam; + QNetworkReply *reply; + QVariant variantData; + QDir downloadDirectory; +}; + +#endif diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 72c892af7..cffae1597 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -77,6 +77,8 @@ extern "C" { #include "qt_styleoverride.hpp" #include "qt_unixmanagerfilter.hpp" #include "qt_util.hpp" +#include "qt_vmmanager_clientsocket.hpp" +#include "qt_vmmanager_mainwindow.hpp" // Void Cast #define VC(x) const_cast(x) @@ -662,6 +664,19 @@ main(int argc, char *argv[]) return 0; } + if (vmm_enabled) { + // VMManagerMain vmm; + // // Hackish until there is a proper solution + // QApplication::setApplicationName("86Box VM Manager"); + // QApplication::setApplicationDisplayName("86Box VM Manager"); + // vmm.show(); + // vmm.exec(); + const auto vmm_main_window = new VMManagerMainWindow(); + vmm_main_window->show(); + QApplication::exec(); + return 0; + } + #ifdef DISCORD discord_load(); #endif @@ -758,6 +773,36 @@ main(int argc, char *argv[]) socket.connectToServer(qgetenv("86BOX_MANAGER_SOCKET")); } + VMManagerClientSocket manager_socket; + if (qgetenv("VMM_86BOX_SOCKET").size()) { + manager_socket.IPCConnect(qgetenv("VMM_86BOX_SOCKET")); + QObject::connect(&manager_socket, &VMManagerClientSocket::pause, main_window, &MainWindow::togglePause); + QObject::connect(&manager_socket, &VMManagerClientSocket::resetVM, main_window, &MainWindow::hardReset); + QObject::connect(&manager_socket, &VMManagerClientSocket::showsettings, main_window, &MainWindow::showSettings); + QObject::connect(&manager_socket, &VMManagerClientSocket::ctrlaltdel, []() { pc_send_cad(); }); + QObject::connect(&manager_socket, &VMManagerClientSocket::request_shutdown, main_window, &MainWindow::close); + QObject::connect(&manager_socket, &VMManagerClientSocket::force_shutdown, []() { + do_stop(); + emit main_window->close(); + }); + QObject::connect(main_window, &MainWindow::vmmRunningStateChanged, &manager_socket, &VMManagerClientSocket::clientRunningStateChanged); + main_window->installEventFilter(&manager_socket); + } + + /* Warn the user about unsupported configs */ + if (cpu_override) { + QMessageBox warningbox(QMessageBox::Icon::Warning, QObject::tr("You are loading an unsupported configuration"), + QObject::tr("CPU type filtering based on selected machine is disabled for this emulated machine.\n\nThis makes it possible to choose a CPU that is otherwise incompatible with the selected machine. However, you may run into incompatibilities with the machine BIOS or other software.\n\nEnabling this setting is not officially supported and any bug reports filed may be closed as invalid."), + QMessageBox::NoButton, main_window); + warningbox.addButton(QObject::tr("Continue"), QMessageBox::AcceptRole); + warningbox.addButton(QObject::tr("Exit"), QMessageBox::RejectRole); + warningbox.exec(); + if (warningbox.result() == QDialog::Accepted) { + confirm_exit_cmdl = 0; /* skip the confirmation prompt without touching the config */ + emit main_window->close(); + } + } + // pc_reset_hard_init(); QTimer onesec; diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 7a9132031..fcf3ea92c 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -2135,6 +2135,7 @@ MainWindow::updateUiPauseState() QString(tr("Pause execution")); ui->actionPause->setIcon(pause_icon); ui->actionPause->setToolTip(tooltip_text); + emit vmmRunningStateChanged(static_cast(dopause)); } void diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index c71dd1ffd..5cf95e7b9 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -13,6 +13,8 @@ #include #include +#include "qt_vmmanager_protocol.hpp" + class MediaMenu; class RendererStack; @@ -63,6 +65,8 @@ signals: void showMessageForNonQtThread(int flags, const QString &header, const QString &message, bool richText, std::atomic_bool* done); void getTitleForNonQtThread(wchar_t *title); + + void vmmRunningStateChanged(VMManagerProtocol::RunningState state); public slots: void showSettings(); void hardReset(); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index a8c25bc2d..8c2586482 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -776,8 +776,8 @@ plat_set_thread_name(void *thread, const char *name) if (pSetThreadDescription) { size_t len = strlen(name) + 1; - wchar_t wname[len + 1]; - mbstowcs(wname, name, len); + wchar_t wname[2048]; + mbstowcs(wname, name, (len >= 1024) ? 1024 : len); pSetThreadDescription(thread ? (HANDLE) thread : GetCurrentThread(), wname); } #else diff --git a/src/qt/qt_updatecheck.cpp b/src/qt/qt_updatecheck.cpp new file mode 100644 index 000000000..83e2b34d9 --- /dev/null +++ b/src/qt/qt_updatecheck.cpp @@ -0,0 +1,360 @@ +/* + * 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. + * + * Update check module + * + * + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ + +#include +#include +#include +#include +#include + +#include "qt_updatecheck.hpp" +#include "qt_downloader.hpp" +#include "qt_updatedetails.hpp" + +extern "C" { +#include <86box/version.h> +} + +UpdateCheck:: +UpdateCheck(const UpdateChannel channel, QObject *parent) : QObject(parent) +{ + updateChannel = channel; + currentVersion = getCurrentVersion(channel); +} + +UpdateCheck::~ +UpdateCheck() + = default; + +void +UpdateCheck::checkForUpdates() +{ + if (updateChannel == UpdateChannel::Stable) { + const auto githubDownloader = new Downloader(Downloader::DownloadLocation::Temp); + connect(githubDownloader, &Downloader::downloadCompleted, this, &UpdateCheck::githubDownloadComplete); + connect(githubDownloader, &Downloader::errorOccurred, this, &UpdateCheck::generalDownloadError); + githubDownloader->download(QUrl(githubReleaseApi), "github_releases.json"); + } else { + const auto jenkinsDownloader = new Downloader(Downloader::DownloadLocation::Temp); + connect(jenkinsDownloader, &Downloader::downloadCompleted, this, &UpdateCheck::jenkinsDownloadComplete); + connect(jenkinsDownloader, &Downloader::errorOccurred, this, &UpdateCheck::generalDownloadError); + jenkinsDownloader->download(jenkinsLatestNReleasesUrl(10), "jenkins_list.json"); + } +} + +void +UpdateCheck::jenkinsDownloadComplete(const QString &filename, const QVariant &varData) +{ + auto generalError = tr("Unable to determine release information"); + auto jenkinsReleaseListResult = parseJenkinsJson(filename); + auto latestVersion = 0; // NOLINT (Default value as a fallback) + + if(!jenkinsReleaseListResult.has_value() || jenkinsReleaseListResult.value().isEmpty()) { + generalDownloadError(generalError); + return; + } + const auto jenkinsReleaseList = jenkinsReleaseListResult.value(); + latestVersion = jenkinsReleaseListResult->first().buildNumber; + + // If we can't determine the local build (blank current version), always show an update as available. + // Callers can adjust accordingly. + // Otherwise, do a comparison with EMU_BUILD_NUM + bool updateAvailable = false; + bool upToDate = true; + if(currentVersion.isEmpty() || EMU_BUILD_NUM < latestVersion) { + updateAvailable = true; + upToDate = false; + } + + const auto updateResult = UpdateResult { + .channel = updateChannel, + .updateAvailable = updateAvailable, + .upToDate = upToDate, + .currentVersion = currentVersion, + .latestVersion = QString::number(latestVersion), + .githubInfo = {}, + .jenkinsInfo = jenkinsReleaseList, + }; + + emit updateCheckComplete(updateResult); +} + +void +UpdateCheck::generalDownloadError(const QString &error) +{ + emit updateCheckError(error); +} + +void +UpdateCheck::githubDownloadComplete(const QString &filename, const QVariant &varData) +{ + const auto generalError = tr("Unable to determine release information"); + const auto githubReleaseListResult = parseGithubJson(filename); + QString latestVersion = "0.0"; + if(!githubReleaseListResult.has_value() || githubReleaseListResult.value().isEmpty()) { + generalDownloadError(generalError); + } + auto githubReleaseList = githubReleaseListResult.value(); + // Warning: this check (using the tag name) relies on a consistent naming scheme: "v" + // where is the release number. For example, 4.2 from v4.2 as the tag name. + // Another option would be parsing the name field which is generally "86Box " but + // either option requires a consistent naming scheme. + latestVersion = githubReleaseList.first().tag_name.replace("v", ""); + for (const auto &release: githubReleaseList) { + qDebug().noquote().nospace() << release.name << ": " << release.html_url << " (" << release.created_at << ")"; + } + + // const auto updateDetails = new UpdateDetails(githubReleaseList, currentVersion); + bool updateAvailable = false; + bool upToDate = true; + if(currentVersion.isEmpty() || (versionCompare(currentVersion, latestVersion) < 0)) { + updateAvailable = true; + upToDate = false; + } + + const auto updateResult = UpdateResult { + .channel = updateChannel, + .updateAvailable = updateAvailable, + .upToDate = upToDate, + .currentVersion = currentVersion, + .latestVersion = latestVersion, + .githubInfo = githubReleaseList, + .jenkinsInfo = {}, + }; + + emit updateCheckComplete(updateResult); + +} + +QUrl +UpdateCheck::jenkinsLatestNReleasesUrl(const int &count) +{ + const auto urlPath = QString("https://ci.86box.net/job/86box/api/json?tree=builds[number,result,timestamp,changeSets[items[commitId,affectedPaths,author[fullName],msg,id]]]{0,%1}").arg(count); + return { urlPath }; +} + +QString +UpdateCheck::getCurrentVersion(const UpdateChannel &updateChannel) +{ + if (updateChannel == UpdateChannel::Stable) { + return {EMU_VERSION}; + } + // If EMU_BUILD_NUM is anything other than the default of zero it was set by the build process + if constexpr (EMU_BUILD_NUM != 0) { + return QString::number(EMU_BUILD_NUM); // NOLINT because EMU_BUILD_NUM is defined as 0 by default and is set at build time + } + // EMU_BUILD_NUM is not set, most likely a local build + return {}; // NOLINT (Having EMU_BUILD_NUM assigned to a default number throws off the linter) +} + +std::optional> +UpdateCheck::parseJenkinsJson(const QString &filename) +{ + QList releaseInfoList; + QFile json_file(filename); + if (!json_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning() << "Couldn't open the json file: error" << json_file.error(); + return std::nullopt; + } + + const QString read_file = json_file.readAll(); + json_file.close(); + + const auto json_doc = QJsonDocument::fromJson(read_file.toUtf8()); + + if (json_doc.isNull()) { + qWarning("Failed to create QJsonDocument, possibly invalid JSON"); + return std::nullopt; + } + + if (!json_doc.isObject()) { + qWarning("JSON does not have the expected format (object in root), cannot continue"); + return std::nullopt; + } + + auto json_object = json_doc.object(); + + // The json contains multiple release + if(json_object.contains("builds") && json_object["builds"].isArray()) { + + QJsonArray builds = json_object["builds"].toArray(); + for (const auto &each_build: builds) { + if (auto build = parseJenkinsRelease(each_build.toObject()); build.has_value() && build.value().result == "SUCCESS") { + releaseInfoList.append(build.value()); + } + } + } else if(json_object.contains("changeSets") && json_object["changeSets"].isArray()) { + // The json contains only one release, as obtained by the lastSuccessfulBuild api + if (const auto build = parseJenkinsRelease(json_object); build.has_value()) { + releaseInfoList.append(build.value()); + } + } else { + qWarning("JSON is missing data or has invalid data, cannot continue"); + qDebug() << json_object; + return std::nullopt; + } + + return releaseInfoList; +} + +std::optional +UpdateCheck::parseJenkinsRelease(const QJsonObject &json) +{ + // The root should contain number, result, and timestamp. + if (!json.contains("number") || !json.contains("result") || !json.contains("timestamp")) { + return std::nullopt; + } + + auto releaseInfo = JenkinsReleaseInfo { + .buildNumber = json["number"].toInt(), + .result = json["result"].toString(), + .timestamp = static_cast(json["timestamp"].toDouble()) + }; + + // Overview + // Each build should contain a changeSets object with an array. Only the first element is needed. + // The first element should be an object containing an items object with an array. + // Each array element in the items object has information releated to the build. More or less: commit data + // In jq parlance it would be similar to `builds[].changeSets[0].items[]` + + // To break down the somewhat complicated if-init statement below: + // * Get the object for `changeSets` + // * Convert the value to array + // * Grab the first element in the array + // Proceed if + // * the element (first in changeSets) is an object that contains the key `items` + if (const auto changeSet = json["changeSets"].toArray().first(); changeSet.isObject() && changeSet.toObject().contains("items")) { + // Then proceed to process each `items` array element + for (const auto &item : changeSet.toObject()["items"].toArray()) { + auto itemObject = item.toObject(); + // Basic validation + if (!itemObject.contains("commitId") || !itemObject.contains("msg") || !itemObject.contains("affectedPaths")) { + return std::nullopt; + } + // Convert the paths for each commit to a string list + QStringList paths; + for (const auto &each_path : itemObject["affectedPaths"].toArray().toVariantList()) { + if (each_path.type() == QVariant::String) { + paths.append(each_path.toString()); + } + } + // Build the structure + const auto releaseItem = JenkinsChangeSetItem { + .buildId = itemObject["commitId"].toString(), + .author = itemObject["author"].toObject()["fullName"].toString(), + .message = itemObject["msg"].toString(), + .affectedPaths = paths, + }; + releaseInfo.changeSetItems.append(releaseItem); + } + } else { + qWarning("Could not parse release information, possibly invalid JSON"); + } + return releaseInfo; +} + +std::optional> +UpdateCheck::parseGithubJson(const QString &filename) +{ + QList releaseInfoList; + QFile json_file(filename); + if (!json_file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning("Couldn't open the json file: error %d", json_file.error()); + return std::nullopt; + } + + const QString read_file = json_file.readAll(); + json_file.close(); + + const auto json_doc = QJsonDocument::fromJson(read_file.toUtf8()); + + if (json_doc.isNull()) { + qWarning("Failed to create QJsonDocument, possibly invalid JSON"); + return std::nullopt; + } + + if (!json_doc.isArray()) { + qWarning("JSON does not have the expected format (array in root), cannot continue"); + return std::nullopt; + } + + auto release_array = json_doc.array(); + + for (const auto &each_release: release_array) { + if (auto release = parseGithubRelease(each_release.toObject()); release.has_value()) { + releaseInfoList.append(release.value()); + } + } + return releaseInfoList; +} +std::optional +UpdateCheck::parseGithubRelease(const QJsonObject &json) +{ + // Perform some basic validation + if (!json.contains("name") || !json.contains("tag_name") || !json.contains("html_url")) { + return std::nullopt; + } + + auto githubRelease = GithubReleaseInfo { + .name = json["name"].toString(), + .tag_name = json["tag_name"].toString(), + .html_url = json["html_url"].toString(), + .target_commitish = json["target_commitish"].toString(), + .created_at = json["created_at"].toString(), + .published_at = json["published_at"].toString(), + .body = json["body"].toString(), + }; + + return githubRelease; +} + +// A simple method to compare version numbers +// Should work for comparing x.y.z and x.y. Missing +// values (parts) will be treated as zeroes +int +UpdateCheck::versionCompare(const QString &version1, const QString &version2) +{ + // Split both + QStringList v1List = version1.split('.'); + QStringList v2List = version2.split('.'); + + // Out of the two versions get the maximum amount of "parts" + const int maxParts = std::max(v1List.size(), v2List.size()); + + // Initialize both with zeros + QVector v1Parts(maxParts, 0); + QVector v2Parts(maxParts, 0); + + for (int i = 0; i < v1List.size(); ++i) { + v1Parts[i] = v1List[i].toInt(); + } + + for (int i = 0; i < v2List.size(); ++i) { + v2Parts[i] = v2List[i].toInt(); + } + + for (int i = 0; i < maxParts; ++i) { + // First version is greater + if (v1Parts[i] > v2Parts[i]) + return 1; + // First version is less + if (v1Parts[i] < v2Parts[i]) + return -1; + } + // They are equal + return 0; +} diff --git a/src/qt/qt_updatecheck.hpp b/src/qt/qt_updatecheck.hpp new file mode 100644 index 000000000..2c04993fc --- /dev/null +++ b/src/qt/qt_updatecheck.hpp @@ -0,0 +1,104 @@ +/* + * 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. + * + * Header for the update check module + * + * + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ + +#ifndef QT_UPDATECHECK_HPP +#define QT_UPDATECHECK_HPP + +#include +#include +#include +#include + +#include + +class UpdateCheck final : public QObject { + Q_OBJECT +public: + enum class UpdateChannel { + Stable, + CI, + }; + + struct JenkinsChangeSetItem { + QString buildId; // sha hash + QString author; // github username + QString message; // commit message + QStringList affectedPaths; // list of files in the change + }; + + struct JenkinsReleaseInfo { + int buildNumber = 0; + QString result; + qint64 timestamp = 0; + QList changeSetItems; + }; + + struct GithubReleaseInfo { + QString name; + QString tag_name; + QString html_url; + QString target_commitish; + QString created_at; + QString published_at; + QString body; + }; + + struct UpdateResult { + UpdateChannel channel; + bool updateAvailable = false; + bool upToDate = false; + QString currentVersion; + QString latestVersion; + QList githubInfo; + QList jenkinsInfo; + }; + + explicit UpdateCheck(UpdateChannel channel, QObject *parent = nullptr); + ~UpdateCheck() override; + void checkForUpdates(); + static int versionCompare(const QString &version1, const QString &version2); + [[nodiscard]] static QString getCurrentVersion(const UpdateChannel &updateChannel = UpdateChannel::Stable); + +signals: + // void updateCheckComplete(const UpdateCheck::UpdateChannel &channel, const QVariant &updateData); + void updateCheckComplete(const UpdateCheck::UpdateResult &result); + void updateCheckError(const QString &errorMsg); + +private: + UpdateChannel updateChannel = UpdateChannel::Stable; + + const QUrl githubReleaseApi = QUrl("https://api.github.com/repos/86box/86Box/releases"); + const QUrl jenkinsLatestApi = QUrl("https://ci.86box.net/job/86box/lastSuccessfulBuild/api/json"); + QString jenkinsLatestVersion; + QString currentVersion; + + static QUrl jenkinsLatestNReleasesUrl(const int &count); + + static std::optional> parseJenkinsJson(const QString &filename); + static std::optional parseJenkinsRelease(const QJsonObject &json); + + static std::optional> parseGithubJson(const QString &filename); + static std::optional parseGithubRelease(const QJsonObject &json); + + +private slots: + void jenkinsDownloadComplete(const QString &filename, const QVariant& varData); + void githubDownloadComplete(const QString &filename, const QVariant& varData); + void generalDownloadError(const QString &error); +}; + +#endif // QT_UPDATECHECK_HPP diff --git a/src/qt/qt_updatecheckdialog.cpp b/src/qt/qt_updatecheckdialog.cpp new file mode 100644 index 000000000..d0cb6941d --- /dev/null +++ b/src/qt/qt_updatecheckdialog.cpp @@ -0,0 +1,90 @@ +/* + * 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. + * + * Update check dialog module + * + * + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ + +#include +#include + +#include "qt_updatecheckdialog.hpp" +#include "ui_qt_updatecheckdialog.h" +#include "qt_updatedetails.hpp" + +extern "C" { +#include <86box/version.h> +} + +UpdateCheckDialog:: +UpdateCheckDialog(const UpdateCheck::UpdateChannel channel, QWidget *parent) : QDialog(parent), ui(new Ui::UpdateCheckDialog), updateCheck(new UpdateCheck(channel)) +{ + ui->setupUi(this); + setWindowTitle(tr("Update check")); + ui->statusLabel->setHidden(true); + updateChannel = channel; + currentVersion = UpdateCheck::getCurrentVersion(updateChannel); + connect(updateCheck, &UpdateCheck::updateCheckError, [=](const QString &errorMsg) { + generalDownloadError(errorMsg); + }); + connect(updateCheck, &UpdateCheck::updateCheckComplete, this, &UpdateCheckDialog::downloadComplete); + + QTimer::singleShot(0, [this] { + updateCheck->checkForUpdates(); + }); +} + +UpdateCheckDialog::~ +UpdateCheckDialog() + = default; + +void +UpdateCheckDialog::generalDownloadError(const QString &error) const +{ + ui->progressBar->setMaximum(100); + ui->progressBar->setValue(100); + ui->statusLabel->setVisible(true); + const auto statusText = tr("There was an error checking for updates:\n\n%1\n\nPlease try again later.").arg(error); + ui->statusLabel->setText(statusText); + ui->buttonBox->setStandardButtons(QDialogButtonBox::Ok); +} + +void +UpdateCheckDialog::downloadComplete(const UpdateCheck::UpdateResult &result) +{ + if (result.upToDate) { + upToDate(); + return; + } + + const auto updateDetails = new UpdateDetails(result); + connect(updateDetails, &QDialog::accepted, [this] { + accept(); + }); + connect(updateDetails, &QDialog::rejected, [this] { + reject(); + }); + updateDetails->exec(); +} + +void +UpdateCheckDialog::upToDate() +{ + ui->titleLabel->setText(tr("Update check complete")); + ui->progressBar->setMaximum(100); + ui->progressBar->setValue(100); + ui->statusLabel->setVisible(true); + const auto statusText = tr("You are running the latest %1 version of 86Box: %2").arg(updateChannel == UpdateCheck::UpdateChannel::Stable ? "stable" : "beta", currentVersion); + ui->statusLabel->setText(statusText); + ui->buttonBox->setStandardButtons(QDialogButtonBox::Ok); +} diff --git a/src/qt/qt_updatecheckdialog.hpp b/src/qt/qt_updatecheckdialog.hpp new file mode 100644 index 000000000..0f1c0dfa8 --- /dev/null +++ b/src/qt/qt_updatecheckdialog.hpp @@ -0,0 +1,47 @@ +/* + * 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. + * + * Header for the update check dialog module + * + * + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ + +#ifndef QT_UPDATECHECKDIALOG_HPP +#define QT_UPDATECHECKDIALOG_HPP + +#include + +#include + +namespace Ui { +class UpdateCheckDialog; +} + +class UpdateCheckDialog final : public QDialog { + Q_OBJECT +public: + explicit UpdateCheckDialog(UpdateCheck::UpdateChannel channel, QWidget *parent = nullptr); + ~UpdateCheckDialog() override; + +private: + Ui::UpdateCheckDialog *ui; + UpdateCheck::UpdateChannel updateChannel = UpdateCheck::UpdateChannel::Stable; + UpdateCheck *updateCheck; + QString currentVersion; + void upToDate(); + +private slots: + void downloadComplete(const UpdateCheck::UpdateResult &result); + void generalDownloadError(const QString &error) const; +}; + +#endif // QT_UPDATECHECKDIALOG_HPP diff --git a/src/qt/qt_updatecheckdialog.ui b/src/qt/qt_updatecheckdialog.ui new file mode 100644 index 000000000..e50a541bb --- /dev/null +++ b/src/qt/qt_updatecheckdialog.ui @@ -0,0 +1,106 @@ + + + UpdateCheckDialog + + + + 0 + 0 + 350 + 134 + + + + + 0 + 0 + + + + Dialog + + + + + + + 0 + 0 + + + + Checking for updates.. + + + Qt::AlignCenter + + + + + + + 0 + + + -1 + + + + + + + Status text here + + + + + + + true + + + Qt::Horizontal + + + QDialogButtonBox::Cancel + + + + + + + + + buttonBox + accepted() + UpdateCheckDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + UpdateCheckDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_updatedetails.cpp b/src/qt/qt_updatedetails.cpp new file mode 100644 index 000000000..1328da732 --- /dev/null +++ b/src/qt/qt_updatedetails.cpp @@ -0,0 +1,111 @@ +/* + * 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. + * + * Update details module + * + * + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ + +#include "qt_updatedetails.hpp" +#include "ui_qt_updatedetails.h" + +#include +#include + + +UpdateDetails:: +UpdateDetails(const UpdateCheck::UpdateResult &updateResult, QWidget *parent) : ui(new Ui::UpdateDetails) +{ + ui->setupUi(this); + setWindowTitle("86Box Update"); + ui->updateTitle->setText("An update to 86Box is available!"); + QString currentVersionText; + QString releaseType = updateResult.channel == UpdateCheck::UpdateChannel::Stable ? tr("version") : tr("build"); + if(!updateResult.currentVersion.isEmpty()) { + currentVersionText = tr("You are currently running %1 %2. ").arg(releaseType, updateResult.currentVersion); + } + + const auto updateDetailsText = tr("%1 %2 is now available. %3Would you like to visit the download page?").arg(releaseType[0].toUpper() + releaseType.mid(1), updateResult.latestVersion, currentVersionText); + ui->updateDetails->setText(updateDetailsText); + + if(updateResult.channel == UpdateCheck::UpdateChannel::Stable) { + ui->updateText->setMarkdown(githubUpdateToMarkdown(updateResult.githubInfo)); + } else { + ui->updateText->setMarkdown(jenkinsUpdateToMarkdown(updateResult.jenkinsInfo)); + } + + const auto downloadButton = new QPushButton(tr("Visit download page")); + ui->buttonBox->addButton(downloadButton, QDialogButtonBox::AcceptRole); + // Override accepted to mean "I want to visit the download page" + connect(ui->buttonBox, &QDialogButtonBox::accepted, [this, updateResult] { + visitDownloadPage(updateResult.channel); + }); + const auto logo = QPixmap(":/assets/86box.png").scaled(QSize(64, 64), Qt::KeepAspectRatio, Qt::SmoothTransformation); + + ui->icon->setPixmap(logo); +} + +UpdateDetails::~ +UpdateDetails() + = default; + +QString +UpdateDetails::jenkinsUpdateToMarkdown(const QList &releaseInfoList) +{ + QStringList fullText; + for (const auto &update : releaseInfoList) { + fullText.append(QString("### Build %1").arg(update.buildNumber)); + fullText.append("Changes:"); + for (const auto &item : update.changeSetItems) { + fullText.append(QString("* %1").arg(item.message)); + } + fullText.append("\n\n\n---\n\n\n"); + } + // pop off the last hr + fullText.removeLast(); + // return fullText.join("\n\n---\n\n"); + return fullText.join("\n"); +} + +QString +UpdateDetails::githubUpdateToMarkdown(const QList &releaseInfoList) +{ + // The github release info can be rather large so we'll only + // display the most recent one + QList singleRelease; + if (!releaseInfoList.isEmpty()) { + singleRelease.append(releaseInfoList.first()); + } + QStringList fullText; + for (const auto &release : singleRelease) { + fullText.append(QString("#### %1").arg(release.name)); + // Github body text should already be in markdown and can just + // be placed here as-is + fullText.append(release.body); + fullText.append("\n\n\n---\n\n\n"); + } + // pop off the last hr + fullText.removeLast(); + return fullText.join("\n"); +} +void +UpdateDetails::visitDownloadPage(const UpdateCheck::UpdateChannel &channel) +{ + switch (channel) { + case UpdateCheck::UpdateChannel::Stable: + QDesktopServices::openUrl(QUrl("https://ci.86box.net/job/86Box/lastSuccessfulBuild/artifact/")); + break; + case UpdateCheck::UpdateChannel::CI: + QDesktopServices::openUrl(QUrl("https://github.com/86Box/86Box/releases/latest")); + break; + } +} diff --git a/src/qt/qt_updatedetails.hpp b/src/qt/qt_updatedetails.hpp new file mode 100644 index 000000000..8c3528e11 --- /dev/null +++ b/src/qt/qt_updatedetails.hpp @@ -0,0 +1,43 @@ +/* + * 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. + * + * Header for the update details module + * + * + * + * Authors: cold-brewed + * + * Copyright 2024 cold-brewed + */ + +#ifndef QT_UPDATEDETAILS_HPP +#define QT_UPDATEDETAILS_HPP + +#include +#include +#include "qt_updatecheck.hpp" + +namespace Ui { +class UpdateDetails; +} + +class UpdateDetails final : public QDialog { + Q_OBJECT +public: + explicit UpdateDetails(const UpdateCheck::UpdateResult &updateResult, QWidget *parent = nullptr); + ~UpdateDetails() override; +private: + Ui::UpdateDetails *ui; + static QString jenkinsUpdateToMarkdown(const QList &releaseInfoList); + static QString githubUpdateToMarkdown(const QList &releaseInfoList); +private slots: + static void visitDownloadPage(const UpdateCheck::UpdateChannel &channel); +}; + + +#endif // QT_UPDATEDETAILS_HPP diff --git a/src/qt/qt_updatedetails.ui b/src/qt/qt_updatedetails.ui new file mode 100644 index 000000000..7b9c0aa2a --- /dev/null +++ b/src/qt/qt_updatedetails.ui @@ -0,0 +1,192 @@ + + + UpdateDetails + + + + 0 + 0 + 700 + 500 + + + + + 600 + 400 + + + + Dialog + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 12 + + + 12 + + + 12 + + + 0 + + + + + + 0 + 0 + + + + + 32 + 0 + + + + + 64 + 16777215 + + + + + + + false + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Title + + + + + + + Details + + + true + + + + + + + Release notes: + + + + + + + true + + + true + + + false + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel + + + + + + + + + buttonBox + accepted() + UpdateDetails + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + UpdateDetails + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_vmmanager_addmachine.cpp b/src/qt/qt_vmmanager_addmachine.cpp new file mode 100644 index 000000000..db40972a1 --- /dev/null +++ b/src/qt/qt_vmmanager_addmachine.cpp @@ -0,0 +1,361 @@ +/* +* 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. +* +* 86Box VM manager add machine wizard +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "qt_vmmanager_addmachine.hpp" + +extern "C" { +#include <86box/86box.h> +} + +// Implementation note: There are several classes in this file: +// One for the main Wizard class and one for each page of the wizard + +VMManagerAddMachine:: +VMManagerAddMachine(QWidget *parent) : QWizard(parent) +{ + setPage(Page_Intro, new IntroPage); + setPage(Page_WithExistingConfig, new WithExistingConfigPage); + setPage(Page_NameAndLocation, new NameAndLocationPage); + setPage(Page_Conclusion, new ConclusionPage); + + // Need to create a better image + // QPixmap originalPixmap(":/assets/86box.png"); + // QPixmap scaledPixmap = originalPixmap.scaled(150, 150, Qt::KeepAspectRatio); + QPixmap wizardPixmap(":/assets/86box-wizard.png"); + +#ifndef Q_OS_MACOS + setWizardStyle(ModernStyle); + // setPixmap(LogoPixmap, scaledPixmap); + // setPixmap(LogoPixmap, wizardPixmap); + // setPixmap(WatermarkPixmap, scaledPixmap); + setPixmap(WatermarkPixmap, wizardPixmap); +#else + // macos + // setPixmap(BackgroundPixmap, scaledPixmap); + setPixmap(BackgroundPixmap, wizardPixmap); +#endif + + // Wizard wants to resize based on image. This keeps the size + setMinimumSize(size()); + setOption(HaveHelpButton, true); + // setPixmap(LogoPixmap, QPixmap(":/settings/qt/icons/86Box-gray.ico")); + + connect(this, &QWizard::helpRequested, this, &VMManagerAddMachine::showHelp); + + setWindowTitle(tr("Add new system wizard")); +} + +void +VMManagerAddMachine::showHelp() +{ + // TBD + static QString lastHelpMessage; + + QString message; + + // Help will depend on the current page + switch (currentId()) { + case Page_Intro: + message = tr("This is the into page."); + break; + default: + message = tr("No help has been added yet, you're on your own."); + break; + } + + if (lastHelpMessage == message) { + message = tr("Did you click help twice?"); + } + + QMessageBox::information(this, tr("Add new system wizard help"), message); + lastHelpMessage = message; +} + +IntroPage:: +IntroPage(QWidget *parent) +{ + setTitle(tr("Introduction")); + + setPixmap(QWizard::WatermarkPixmap, QPixmap(":/assets/qt/assets/86box.png")); + + topLabel = new QLabel(tr("This will help you add a new system to 86Box.")); + // topLabel = new QLabel(tr("This will help you add a new system to 86Box.\n\n Choose \"New configuration\" if you'd like to create a new machine.\n\nChoose \"Use existing configuration\" if you'd like to paste in an existing configuration from elsewhere.")); + topLabel->setWordWrap(true); + + newConfigRadioButton = new QRadioButton(tr("New configuration")); + // auto newDescription = new QLabel(tr("Choose this option to start with a fresh configuration.")); + existingConfigRadioButton = new QRadioButton(tr("Use existing configuraion")); + // auto existingDescription = new QLabel(tr("Use this option if you'd like to paste in the configuration file from an existing system.")); + newConfigRadioButton->setChecked(true); + + const auto layout = new QVBoxLayout(); + layout->addWidget(topLabel); + layout->addWidget(newConfigRadioButton); + // layout->addWidget(newDescription); + layout->addWidget(existingConfigRadioButton); + // layout->addWidget(existingDescription); + + setLayout(layout); +} + +int +IntroPage::nextId() const +{ + if (newConfigRadioButton->isChecked()) { + return VMManagerAddMachine::Page_NameAndLocation; + } else { + return VMManagerAddMachine::Page_WithExistingConfig; + } +} + +WithExistingConfigPage:: +WithExistingConfigPage(QWidget *parent) +{ + setTitle(tr("Use existing configuration")); + + const auto topLabel = new QLabel(tr("Paste the contents of the existing configuration file into the box below.")); + topLabel->setWordWrap(true); + + existingConfiguration = new QPlainTextEdit(); + connect(existingConfiguration, &QPlainTextEdit::textChanged, this, &WithExistingConfigPage::completeChanged); + registerField("existingConfiguration*", this, "configuration"); + + const auto layout = new QVBoxLayout(); + layout->addWidget(topLabel); + layout->addWidget(existingConfiguration); + const auto loadFileButton = new QPushButton(); + const auto loadFileLabel = new QLabel(tr("Load configuration from file")); + const auto hLayout = new QHBoxLayout(); + loadFileButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_FileIcon)); + loadFileButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + connect(loadFileButton, &QPushButton::clicked, this, &WithExistingConfigPage::chooseExistingConfigFile); + hLayout->addWidget(loadFileButton); + hLayout->addWidget(loadFileLabel); + layout->addLayout(hLayout); + setLayout(layout); +} + +void +WithExistingConfigPage::chooseExistingConfigFile() +{ + // TODO: FIXME: This is using the CLI arg and needs to instead use a proper variable + const auto startDirectory = QString(vmm_path); + const auto selectedConfigFile = QFileDialog::getOpenFileName(this, tr("Choose configuration file"), + startDirectory, + tr("86Box configuration files (86box.cfg)")); + // Empty value means the dialog was canceled + if (!selectedConfigFile.isEmpty()) { + QFile configFile(selectedConfigFile); + if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + QMessageBox::critical(this, tr("Configuration read failed"), tr("Unable to open the selected configuration file for reading: %1").arg(configFile.errorString())); + return; + } + const QString configFileContents = configFile.readAll(); + existingConfiguration->setPlainText(configFileContents); + configFile.close(); + emit completeChanged(); + } +} + +QString +WithExistingConfigPage::configuration() const +{ + return existingConfiguration->toPlainText(); +} +void +WithExistingConfigPage::setConfiguration(const QString &configuration) +{ + if (configuration != existingConfiguration->toPlainText()) { + existingConfiguration->setPlainText(configuration); + emit configurationChanged(configuration); + } +} + +int +WithExistingConfigPage::nextId() const +{ + return VMManagerAddMachine::Page_NameAndLocation; +} + +bool +WithExistingConfigPage::isComplete() const +{ + return !existingConfiguration->toPlainText().isEmpty(); +} + +NameAndLocationPage:: +NameAndLocationPage(QWidget *parent) +{ + setTitle(tr("System name and location")); + + dirValidate = QRegularExpression(R"(^[^\\/:*?"<>|\s]+$)"); + + const auto topLabel = new QLabel(tr("Enter the name of the system and choose the location")); + topLabel->setWordWrap(true); + + const auto chooseDirectoryButton = new QPushButton(); + chooseDirectoryButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirIcon)); + + const auto systemNameLabel = new QLabel(tr("System Name")); + systemName = new QLineEdit(); + // Special event filter to override enter key + systemName->installEventFilter(this); + registerField("systemName*", systemName); + systemNameValidation = new QLabel(); + + const auto systemLocationLabel = new QLabel(tr("System Location")); + systemLocation = new QLineEdit(); + // TODO: FIXME: This is using the CLI arg and needs to instead use a proper variable + systemLocation->setText(QDir::toNativeSeparators(vmm_path)); + registerField("systemLocation*", systemLocation); + systemLocationValidation = new QLabel(); + systemLocationValidation->setWordWrap(true); + + const auto layout = new QGridLayout(); + layout->addWidget(topLabel, 0, 0, 1, -1); + // Spacer row + layout->setRowMinimumHeight(1, 20); + layout->addWidget(systemNameLabel, 2, 0); + layout->addWidget(systemName, 2, 1); + // Validation text, appears only as necessary + layout->addWidget(systemNameValidation, 3, 0, 1, -1); + // Set height on validation because it may not always be present + layout->setRowMinimumHeight(3, 20); + + // Another spacer + layout->setRowMinimumHeight(4, 20); + layout->addWidget(systemLocationLabel, 5, 0); + layout->addWidget(systemLocation, 5, 1); + layout->addWidget(chooseDirectoryButton, 5, 2); + // Validation text + layout->addWidget(systemLocationValidation, 6, 0, 1, -1); + layout->setRowMinimumHeight(6, 20); + + setLayout(layout); + + + connect(chooseDirectoryButton, &QPushButton::clicked, this, &NameAndLocationPage::chooseDirectoryLocation); +} + +int +NameAndLocationPage::nextId() const +{ + return VMManagerAddMachine::Page_Conclusion; +} + +void +NameAndLocationPage::chooseDirectoryLocation() +{ + // TODO: FIXME: This is pulling in the CLI directory! Needs to be set properly elsewhere + const auto directory = QFileDialog::getExistingDirectory(this, "Choose directory", QDir(vmm_path).path()); + systemLocation->setText(QDir::toNativeSeparators(directory)); + emit completeChanged(); +} +bool +NameAndLocationPage::isComplete() const +{ + bool nameValid = false; + bool locationValid = false; + // return true if complete + if (systemName->text().isEmpty()) { + systemNameValidation->setText(tr("Please enter a system name")); + } else if (!systemName->text().contains(dirValidate)) { + systemNameValidation->setText(tr("System name cannot contain a space or certain characters")); + } else if (const QDir newDir = QDir::cleanPath(systemLocation->text() + "/" + systemName->text()); newDir.exists()) { + systemNameValidation->setText(tr("System name already exists")); + } else { + systemNameValidation->clear(); + nameValid = true; + } + + if (systemLocation->text().isEmpty()) { + systemLocationValidation->setText(tr("Please enter a directory for the system")); + } else if (const auto dir = QDir(systemLocation->text()); !dir.exists()) { + systemLocationValidation->setText(tr("Directory does not exist")); + } else { + systemLocationValidation->setText("A new directory for the system will be created in the selected directory above"); + locationValid = true; + } + + return nameValid && locationValid; +} +bool +NameAndLocationPage::eventFilter(QObject *watched, QEvent *event) +{ + // Override the enter key to hit the next wizard button + // if the validator (isComplete) is satisfied + if (event->type() == QEvent::KeyPress) { + const auto keyEvent = dynamic_cast(event); + if (keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) { + // Only advance if the validator is satisfied (isComplete) + if(const auto wizard = qobject_cast(this->wizard())) { + if (wizard->currentPage()->isComplete()) { + wizard->next(); + } + } + // Discard the key event + return true; + } + } + return QWizardPage::eventFilter(watched, event); +} + +ConclusionPage:: +ConclusionPage(QWidget *parent) +{ + setTitle(tr("Complete")); + + topLabel = new QLabel(tr("The wizard will now launch the configuration for the new system.")); + topLabel->setWordWrap(true); + + const auto systemNameLabel = new QLabel(tr("System name:")); + systemNameLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + systemName = new QLabel(); + const auto systemLocationLabel = new QLabel(tr("System location:")); + systemLocationLabel->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + systemLocation = new QLabel(); + + const auto layout = new QGridLayout(); + layout->addWidget(topLabel, 0, 0, 1, -1); + layout->setRowMinimumHeight(1, 20); + layout->addWidget(systemNameLabel, 2, 0); + layout->addWidget(systemName, 2, 1); + layout->addWidget(systemLocationLabel, 3, 0); + layout->addWidget(systemLocation, 3, 1); + + setLayout(layout); +} + +// initializePage() runs after the page has been created with the constructor +void +ConclusionPage::initializePage() +{ + const auto finalPath = QDir::cleanPath(field("systemLocation").toString() + "/" + field("systemName").toString()); + const auto nativePath = QDir::toNativeSeparators(finalPath); + const auto systemNameDisplay = field("systemName").toString(); + + systemName->setText(systemNameDisplay); + systemLocation->setText(nativePath); +} diff --git a/src/qt/qt_vmmanager_addmachine.hpp b/src/qt/qt_vmmanager_addmachine.hpp new file mode 100644 index 000000000..c1355b471 --- /dev/null +++ b/src/qt/qt_vmmanager_addmachine.hpp @@ -0,0 +1,115 @@ +/* +* 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. +* +* Header for 86Box VM manager add machine wizard +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef QT_VMMANAGER_ADDMACHINE_H +#define QT_VMMANAGER_ADDMACHINE_H + +#include +#include +#include +#include +#include +#include + +// Implementation note: There are several classes in this header: +// One for the main Wizard class and one for each page of the wizard + +class VMManagerAddMachine final : public QWizard { + Q_OBJECT + +public: + enum { + Page_Intro, + Page_Fresh, + Page_WithExistingConfig, + Page_NameAndLocation, + Page_Conclusion + }; + + explicit VMManagerAddMachine(QWidget *parent = nullptr); + +private slots: + void showHelp(); +}; + +class IntroPage : public QWizardPage { + Q_OBJECT + +public: + explicit IntroPage(QWidget *parent = nullptr); + [[nodiscard]] int nextId() const override; + +private: + QLabel *topLabel; + QRadioButton *newConfigRadioButton; + QRadioButton *existingConfigRadioButton; +}; + +class WithExistingConfigPage final : public QWizardPage { + Q_OBJECT + Q_PROPERTY(QString configuration READ configuration WRITE setConfiguration NOTIFY configurationChanged) + +public: + explicit WithExistingConfigPage(QWidget *parent = nullptr); + // These extra functions are required to register QPlainTextEdit fields + [[nodiscard]] QString configuration() const; + void setConfiguration(const QString &configuration); +signals: + void configurationChanged(const QString &configuration); +private: + QPlainTextEdit *existingConfiguration; +private slots: + void chooseExistingConfigFile(); +protected: + [[nodiscard]] int nextId() const override; + [[nodiscard]] bool isComplete() const override; + +}; + +class NameAndLocationPage final : public QWizardPage { + Q_OBJECT + +public: + explicit NameAndLocationPage(QWidget *parent = nullptr); + [[nodiscard]] int nextId() const override; +private: + QLineEdit *systemName; + QLineEdit *systemLocation; + QLabel *systemNameValidation; + QLabel *systemLocationValidation; + QRegularExpression dirValidate; +private slots: + void chooseDirectoryLocation(); +protected: + [[nodiscard]] bool isComplete() const override; + bool eventFilter(QObject *watched, QEvent *event) override; + +}; + +class ConclusionPage final : public QWizardPage { + Q_OBJECT +public: + explicit ConclusionPage(QWidget *parent = nullptr); +private: + QLabel *topLabel; + QLabel *systemName; + QLabel *systemLocation; +protected: + void initializePage() override; +}; + +#endif // QT_VMMANAGER_ADDMACHINE_H \ No newline at end of file diff --git a/src/qt/qt_vmmanager_clientsocket.cpp b/src/qt/qt_vmmanager_clientsocket.cpp new file mode 100644 index 000000000..1035a846c --- /dev/null +++ b/src/qt/qt_vmmanager_clientsocket.cpp @@ -0,0 +1,236 @@ +/* +* 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. +* +* 86Box VM manager client socket module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include "qt_vmmanager_clientsocket.hpp" +#include "qt_vmmanager_protocol.hpp" +#include +#include +#include + +extern "C" { +#include "86box/plat.h" +} + +VMManagerClientSocket::VMManagerClientSocket(QObject* obj) : server_connected(false) +{ + socket = new QLocalSocket; + +} + +void +VMManagerClientSocket::dataReady() +{ + // emit signal? + QDataStream stream(socket); + stream.setVersion(QDataStream::Qt_5_7); + QByteArray jsonData; + for (;;) { + // start a transaction + stream.startTransaction(); + // try to read the data + stream >> jsonData; + if (stream.commitTransaction()) { + // first try to successfully read some data + // need to also make sure it's valid json + QJsonParseError parse_error{}; + // try to create a document with the data received + const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parse_error); + if (parse_error.error == QJsonParseError::NoError) { + // the data received was valid json + if (jsonDoc.isObject()) { + // and is a valid json object + // parse the json + jsonReceived(jsonDoc.object()); + } + } + // If the received data isn't valid json, + // loop and try to read more if available + } else { + // read failed, socket is reverted to its previous state (before the transaction) + // Exit the loop and wait for more data to become available + break; + } + } + +} + +bool +VMManagerClientSocket::IPCConnect(const QString &server) +{ + server_name = server; + connect(socket, &QLocalSocket::connected, this, &VMManagerClientSocket::connected); + connect(socket, &QLocalSocket::disconnected, this, &VMManagerClientSocket::disconnected); + connect(socket, &QLocalSocket::errorOccurred, this, &VMManagerClientSocket::connectionError); + connect(socket, &QLocalSocket::readyRead, this, &VMManagerClientSocket::dataReady); + + socket->connectToServer(server_name); + + if(!socket->isValid()) { + qInfo("Could not connect to server: %s", qPrintable(socket->errorString())); + return false; + } + + qInfo("Connection Successful"); + return true; +} + +void +VMManagerClientSocket::connected() const +{ + // TODO: signal + qDebug("Connected to %s", qPrintable(server_name)); +} + +void +VMManagerClientSocket::disconnected() const +{ + // TODO: signal + qDebug("Disconnected from %s", qPrintable(server_name)); +} + +void +VMManagerClientSocket::sendMessage(const VMManagerProtocol::ClientMessage protocol_message) const +{ + sendMessageFull(protocol_message, QStringList(), QJsonObject()); +} + +void +VMManagerClientSocket::sendMessageWithList(const VMManagerProtocol::ClientMessage protocol_message, const QStringList &list) const +{ + sendMessageFull(protocol_message, list, QJsonObject()); +} + +void +VMManagerClientSocket::sendMessageWithObject(const VMManagerProtocol::ClientMessage protocol_message, const QJsonObject &json) const +{ + sendMessageFull(protocol_message, QStringList(), json); +} + +void +VMManagerClientSocket::sendMessageFull(const VMManagerProtocol::ClientMessage protocol_message, const QStringList &list, const QJsonObject &json) const +{ + QDataStream clientStream(socket); + clientStream.setVersion(QDataStream::Qt_5_7); + auto packet = new VMManagerProtocol(VMManagerProtocol::Sender::Client); + auto jsonMessage = packet->protocolClientMessage(protocol_message); + if (!list.isEmpty()) { + jsonMessage["list"] = QJsonArray::fromStringList(list); + } + // TODO: Add the logic for including objects + if(!json.isEmpty()) { + jsonMessage["params"] = json; + } + clientStream << QJsonDocument(jsonMessage).toJson(QJsonDocument::Compact); +} + +void +VMManagerClientSocket::jsonReceived(const QJsonObject &json) +{ + // The serialization portion has already validated the message as json. + // Ensure it has the required fields + if (!VMManagerProtocol::hasRequiredFields(json)) { + // TODO: Error handling of some sort, emit signals + qDebug("Invalid message received from client: required fields missing. Object:"); + qDebug() << json; + return; + } + // qDebug() << Q_FUNC_INFO << json; + + // Parsing happens here. When adding new types, make sure to first add them + // to VMManagerProtocol::ManagerMessage and then add it to the list here. + // If a signal needs to be emitted, add that as well and connect to slots + // as appropriate. + + switch (VMManagerProtocol::getManagerMessageType(json)) { + case VMManagerProtocol::ManagerMessage::Pause: + qDebug("Pause command received from manager"); + emit pause(); + break; + case VMManagerProtocol::ManagerMessage::ResetVM: + qDebug("Reset VM command received from manager"); + emit resetVM(); + break; + case VMManagerProtocol::ManagerMessage::ShowSettings: + qDebug("Show settings command received from manager"); + emit showsettings(); + break; + case VMManagerProtocol::ManagerMessage::CtrlAltDel: + qDebug("CtrlAltDel command received from manager"); + emit ctrlaltdel(); + break; + case VMManagerProtocol::ManagerMessage::RequestShutdown: + qDebug("RequestShutdown command received from manager"); + emit request_shutdown(); + break; + case VMManagerProtocol::ManagerMessage::ForceShutdown: + qDebug("ForceShutdown command received from manager"); + emit force_shutdown(); + break; + case VMManagerProtocol::ManagerMessage::RequestStatus: + qDebug("Status request command received from manager"); + break; + default: + qDebug("Unknown client message type received:"); + qDebug() << json; + break; + } +} + +void +VMManagerClientSocket::connectionError(const QLocalSocket::LocalSocketError socketError) +{ + qInfo("A connection error has occurred: "); + switch (socketError) { + case QLocalSocket::ServerNotFoundError: + qInfo("Server not found"); + break; + case QLocalSocket::ConnectionRefusedError: + qInfo("Connection refused"); + break; + case QLocalSocket::PeerClosedError: + qInfo("Peer closed"); + break; + default: + qInfo() << "QLocalSocket::LocalSocketError " << socketError; + break; + } +} + +bool +VMManagerClientSocket::eventFilter(QObject *obj, QEvent *event) +{ + if (socket->state() == QLocalSocket::ConnectedState) { + VMManagerProtocol::RunningState running_state; + if (event->type() == QEvent::WindowBlocked) { + running_state = dopause ? VMManagerProtocol::RunningState::PausedWaiting : VMManagerProtocol::RunningState::RunningWaiting; + clientRunningStateChanged(running_state); + } else if (event->type() == QEvent::WindowUnblocked) { + running_state = dopause ? VMManagerProtocol::RunningState::Paused : VMManagerProtocol::RunningState::Running; + clientRunningStateChanged(running_state); + } + } + return QObject::eventFilter(obj, event); +} + +void +VMManagerClientSocket::clientRunningStateChanged(VMManagerProtocol::RunningState state) const +{ + QJsonObject extra_object; + extra_object["status"] = static_cast(state); + sendMessageWithObject(VMManagerProtocol::ClientMessage::RunningStateChanged, extra_object); + +} diff --git a/src/qt/qt_vmmanager_clientsocket.hpp b/src/qt/qt_vmmanager_clientsocket.hpp new file mode 100644 index 000000000..10a053347 --- /dev/null +++ b/src/qt/qt_vmmanager_clientsocket.hpp @@ -0,0 +1,71 @@ +/* +* 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. +* +* Header file for 86Box VM manager client socket module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef QT_VMMANAGER_CLIENTSOCKET_HPP +#define QT_VMMANAGER_CLIENTSOCKET_HPP + +#include "qt_vmmanager_protocol.hpp" +#include +#include +#include +#include + +class VMManagerClientSocket final : public QObject { + Q_OBJECT + +public: + explicit VMManagerClientSocket(QObject* object = nullptr); + bool IPCConnect(const QString &server); + +signals: + void pause(); + void ctrlaltdel(); + void showsettings(); + void resetVM(); + void request_shutdown(); + void force_shutdown(); + void dialogstatus(bool open); + +public slots: + void clientRunningStateChanged(VMManagerProtocol::RunningState state) const; + +private: + QString server_name; + QLocalSocket *socket; + bool server_connected; + void connected() const; + void disconnected() const; + static void connectionError(QLocalSocket::LocalSocketError socketError); + + // Main convenience send function + void sendMessage(VMManagerProtocol::ClientMessage protocol_message) const; + // Send message with optional params array convenience function + void sendMessageWithList(VMManagerProtocol::ClientMessage protocol_message, const QStringList &list) const; + // Send message with optional json object convenience function + void sendMessageWithObject(VMManagerProtocol::ClientMessage protocol_message, const QJsonObject &json) const; + // Full send message function called by all convenience functions + void sendMessageFull(VMManagerProtocol::ClientMessage protocol_message, const QStringList &list, const QJsonObject &json) const; + void jsonReceived(const QJsonObject &json); + + void dataReady(); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +}; + +#endif // QT_VMMANAGER_CLIENTSOCKET_HPP diff --git a/src/qt/qt_vmmanager_config.cpp b/src/qt/qt_vmmanager_config.cpp new file mode 100644 index 000000000..08bf4e7c4 --- /dev/null +++ b/src/qt/qt_vmmanager_config.cpp @@ -0,0 +1,76 @@ +/* +* 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. +* +* 86Box VM manager configuration module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include +#include +#include "qt_vmmanager_config.hpp" + +extern "C" { +#include <86box/plat.h> +} + +VMManagerConfig::VMManagerConfig(const ConfigType type, const QString& section) +{ + char BUF[256]; + plat_get_global_config_dir(BUF, 255); + const auto configDir = QString(BUF); + const auto configFile = QDir::cleanPath(configDir + "/" + "vmm.ini"); + + config_type = type; + + settings = new QSettings(configFile, QSettings::IniFormat, this); + settings->setFallbacksEnabled(false); + if(type == ConfigType::System && !section.isEmpty()) { + settings->beginGroup(section); + } +} + +VMManagerConfig::~VMManagerConfig() { + settings->endGroup(); +} + +QString +VMManagerConfig::getStringValue(const QString& key) const +{ + const auto value = settings->value(key); + // An invalid QVariant with toString will give a default QString value which is blank. + // Therefore any variables that do not exist will return blank strings + return value.toString(); +} + +void +VMManagerConfig::setStringValue(const QString &key, const QString &value) const +{ + if (value.isEmpty()) { + remove(key); + return; + } + settings->setValue(key, value); +} + +void +VMManagerConfig::remove(const QString &key) const +{ + settings->remove(key); +} + +void +VMManagerConfig::sync() const +{ + settings->sync(); +} + diff --git a/src/qt/qt_vmmanager_config.hpp b/src/qt/qt_vmmanager_config.hpp new file mode 100644 index 000000000..bc63aaa03 --- /dev/null +++ b/src/qt/qt_vmmanager_config.hpp @@ -0,0 +1,46 @@ +/* +* 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. +* +* Header for the 86Box VM manager configuration module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef QT_VMMANAGER_CONFIG_H +#define QT_VMMANAGER_CONFIG_H + +#include + +class VMManagerConfig : QObject { + Q_OBJECT + +public: + enum class ConfigType { + General, + System, + }; + Q_ENUM(ConfigType); + + explicit VMManagerConfig(ConfigType type, const QString& section = {}); + ~VMManagerConfig() override; + [[nodiscard]] QString getStringValue(const QString& key) const; + void setStringValue(const QString& key, const QString& value) const; + void remove(const QString &key) const; + + void sync() const; + + QSettings *settings; + ConfigType config_type; + QString system_name; +}; + +#endif // QT_VMMANAGER_CONFIG_H \ No newline at end of file diff --git a/src/qt/qt_vmmanager_details.cpp b/src/qt/qt_vmmanager_details.cpp new file mode 100644 index 000000000..23fe5377e --- /dev/null +++ b/src/qt/qt_vmmanager_details.cpp @@ -0,0 +1,398 @@ +/* +* 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. +* +* 86Box VM manager system details module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include +#include +#include + +#include "qt_vmmanager_details.hpp" +#include "ui_qt_vmmanager_details.h" + +#ifdef Q_OS_WINDOWS +extern bool windows_is_light_theme(); +#endif + +VMManagerDetails::VMManagerDetails(QWidget *parent) : + QWidget(parent), ui(new Ui::VMManagerDetails) { + ui->setupUi(this); + + const auto leftColumnLayout = qobject_cast(ui->leftColumn->layout()); + + // Each section here gets its own VMManagerDetailSection, named in the constructor. + // When a system is selected in the list view it is updated through this object + // See updateData() for the implementation + + systemSection = new VMManagerDetailSection(tr("System", "Header for System section in VM Manager Details")); + ui->leftColumn->layout()->addWidget(systemSection); + // These horizontal lines are used for the alternate layout which may possibly + // be a preference one day. + // ui->leftColumn->layout()->addWidget(createHorizontalLine()); + + videoSection = new VMManagerDetailSection(tr("Display", "Header for Display section in VM Manager Details")); + ui->leftColumn->layout()->addWidget(videoSection); + // ui->leftColumn->layout()->addWidget(createHorizontalLine()); + + storageSection = new VMManagerDetailSection(tr("Storage", "Header for Storage section in VM Manager Details")); + ui->leftColumn->layout()->addWidget(storageSection); + // ui->leftColumn->layout()->addWidget(createHorizontalLine()); + + audioSection = new VMManagerDetailSection(tr("Audio", "Header for Audio section in VM Manager Details")); + ui->leftColumn->layout()->addWidget(audioSection); + // ui->leftColumn->layout()->addWidget(createHorizontalLine()); + + networkSection = new VMManagerDetailSection(tr("Network", "Header for Network section in VM Manager Details")); + ui->leftColumn->layout()->addWidget(networkSection); + // ui->leftColumn->layout()->addWidget(createHorizontalLine()); + + inputSection = new VMManagerDetailSection(tr("Input Devices", "Header for Input section in VM Manager Details")); + ui->leftColumn->layout()->addWidget(inputSection); + // ui->leftColumn->layout()->addWidget(createHorizontalLine()); + + portsSection = new VMManagerDetailSection(tr("Ports", "Header for Input section in VM Manager Details")); + ui->leftColumn->layout()->addWidget(portsSection); + + // This is like adding a spacer + leftColumnLayout->addStretch(); + + // Event filter for the notes to save when it loses focus + ui->notesTextEdit->installEventFilter(this); + + // Default screenshot label and thumbnail (image inside the label) sizes + screenshotThumbnailSize = QSize(240, 160); + + // Set the icons for the screenshot navigation buttons + ui->screenshotNext->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowRight)); + ui->screenshotPrevious->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowLeft)); + ui->screenshotNextTB->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowRight)); + ui->screenshotPreviousTB->setIcon(QApplication::style()->standardIcon(QStyle::SP_ArrowLeft)); + // Disabled by default + ui->screenshotNext->setEnabled(false); + ui->screenshotPrevious->setEnabled(false); + ui->screenshotNextTB->setEnabled(false); + ui->screenshotPreviousTB->setEnabled(false); + // Connect their signals + connect(ui->screenshotNext, &QPushButton::clicked, this, &VMManagerDetails::nextScreenshot); + connect(ui->screenshotNextTB, &QToolButton::clicked, this, &VMManagerDetails::nextScreenshot); + connect(ui->screenshotPreviousTB, &QToolButton::clicked, this, &VMManagerDetails::previousScreenshot); + connect(ui->screenshotPrevious, &QPushButton::clicked, this, &VMManagerDetails::previousScreenshot); + // These push buttons can be taken out if the tool buttons stay + ui->screenshotNext->setVisible(false); + ui->screenshotPrevious->setVisible(false); + QString toolButtonStyleSheet; + // Simple method to try and determine if light mode is enabled +#ifdef Q_OS_WINDOWS + const bool lightMode = windows_is_light_theme(); +#else + const bool lightMode = QApplication::palette().window().color().value() > QApplication::palette().windowText().color().value(); +#endif + if (lightMode) { + toolButtonStyleSheet = "QToolButton {background: transparent; border: none; padding: 5px} QToolButton:hover {background: palette(midlight)} QToolButton:pressed {background: palette(mid)}"; + } else { +#ifndef Q_OS_WINDOWS + toolButtonStyleSheet = "QToolButton {background: transparent; border: none; padding: 5px} QToolButton:hover {background: palette(dark)} QToolButton:pressed {background: palette(mid)}"; +#else + toolButtonStyleSheet = "QToolButton {padding: 5px}"; +#endif + } + ui->ssNavTBHolder->setStyleSheet(toolButtonStyleSheet); + + // Experimenting + startPauseButton = new QToolButton(); + startPauseButton->setIcon(QIcon(":/menuicons/qt/icons/run.ico")); + startPauseButton->setAutoRaise(true); + startPauseButton->setEnabled(false); + startPauseButton->setToolTip(tr("Start")); + ui->toolButtonHolder->setStyleSheet(toolButtonStyleSheet); + resetButton = new QToolButton(); + resetButton->setIcon(QIcon(":/menuicons/qt/icons/hard_reset.ico")); + resetButton->setEnabled(false); + resetButton->setToolTip(tr("Hard reset")); + stopButton = new QToolButton(); + stopButton->setIcon(QIcon(":/menuicons/qt/icons/acpi_shutdown.ico")); + stopButton->setEnabled(false); + stopButton->setToolTip(tr("Force shutdown")); + configureButton = new QToolButton(); + configureButton->setIcon(QIcon(":/menuicons/qt/icons/settings.ico")); + configureButton->setEnabled(false); + configureButton->setToolTip(tr("Settings...")); + cadButton = new QToolButton(); + cadButton->setIcon(QIcon(":menuicons/qt/icons/send_cad.ico")); + cadButton->setEnabled(false); + cadButton->setToolTip(tr("Ctrl+Alt+Del")); + + ui->toolButtonHolder->layout()->addWidget(configureButton); + ui->toolButtonHolder->layout()->addWidget(resetButton); + ui->toolButtonHolder->layout()->addWidget(stopButton); + ui->toolButtonHolder->layout()->addWidget(startPauseButton); + ui->toolButtonHolder->layout()->addWidget(cadButton); + + ui->notesTextEdit->setEnabled(false); + + sysconfig = new VMManagerSystem(); +} + +VMManagerDetails::~VMManagerDetails() { + delete ui; +} + +void +VMManagerDetails::updateData(VMManagerSystem *passed_sysconfig) { + + // Set the scrollarea background but also set the scroll bar to none. Otherwise it will also + // set the scrollbar background to the same. +#ifdef Q_OS_WINDOWS + extern bool windows_is_light_theme(); + if (windows_is_light_theme()) +#endif + { + ui->scrollArea->setStyleSheet("QWidget {background-color: palette(light)} QScrollBar{ background-color: none }"); + ui->systemLabel->setStyleSheet("background-color: palette(midlight);"); + } + // Margins are a little different on macos +#ifdef Q_OS_MACOS + ui->systemLabel->setMargin(15); +#else + ui->systemLabel->setMargin(10); +#endif + + // disconnect old signals before assigning the passed systemconfig object + disconnect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::startButtonPressed); + disconnect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::pauseButtonPressed); + disconnect(resetButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::restartButtonPressed); + disconnect(stopButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::shutdownForceButtonPressed); + disconnect(configureButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::launchSettings); + disconnect(cadButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::cadButtonPressed); + + sysconfig = passed_sysconfig; + connect(resetButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::restartButtonPressed); + connect(stopButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::shutdownForceButtonPressed); + connect(configureButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::launchSettings); + connect(cadButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::cadButtonPressed); + cadButton->setEnabled(true); + + bool running = sysconfig->getProcessStatus() == VMManagerSystem::ProcessStatus::Running || + sysconfig->getProcessStatus() == VMManagerSystem::ProcessStatus::RunningWaiting; + if(running) { + startPauseButton->setIcon(QIcon(":/menuicons/qt/icons/pause.ico")); + connect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::pauseButtonPressed); + } else { + startPauseButton->setIcon(QIcon(":/menuicons/qt/icons/run.ico")); + connect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::startButtonPressed); + } + startPauseButton->setEnabled(true); + configureButton->setEnabled(true); + + // Each detail section here has its own VMManagerDetailSection. + // When a system is selected in the list view it is updated here, through this object: + // * First you clear it with VMManagerDetailSection::clear() + // * Then you add each line with VMManagerDetailSection::addSection() + + // System + systemSection->clear(); + systemSection->addSection("Machine", passed_sysconfig->getDisplayValue(Display::Name::Machine)); + systemSection->addSection("CPU", passed_sysconfig->getDisplayValue(Display::Name::CPU)); + systemSection->addSection("Memory", passed_sysconfig->getDisplayValue(Display::Name::Memory)); + + // Video + videoSection->clear(); + videoSection->addSection("Video", passed_sysconfig->getDisplayValue(Display::Name::Video)); + if(!passed_sysconfig->getDisplayValue(Display::Name::Voodoo).isEmpty()) { + videoSection->addSection("Voodoo", passed_sysconfig->getDisplayValue(Display::Name::Voodoo)); + } + + // Disks + storageSection->clear(); + storageSection->addSection("Disks", passed_sysconfig->getDisplayValue(Display::Name::Disks)); + storageSection->addSection("Floppy", passed_sysconfig->getDisplayValue(Display::Name::Floppy)); + storageSection->addSection("CD-ROM", passed_sysconfig->getDisplayValue(Display::Name::CD)); + storageSection->addSection("SCSI", passed_sysconfig->getDisplayValue(Display::Name::SCSIController)); + + // Audio + audioSection->clear(); + audioSection->addSection("Audio", passed_sysconfig->getDisplayValue(Display::Name::Audio)); + audioSection->addSection("MIDI Out", passed_sysconfig->getDisplayValue(Display::Name::MidiOut)); + + // Network + networkSection->clear(); + networkSection->addSection("NIC", passed_sysconfig->getDisplayValue(Display::Name::NIC)); + + // Input + inputSection->clear(); + inputSection->addSection(tr("Mouse"), passed_sysconfig->getDisplayValue(Display::Name::Mouse)); + inputSection->addSection(tr("Joystick"), passed_sysconfig->getDisplayValue(Display::Name::Joystick)); + + // Ports + portsSection->clear(); + portsSection->addSection(tr("Serial Ports"), passed_sysconfig->getDisplayValue(Display::Name::Serial)); + portsSection->addSection(tr("Parallel Ports"), passed_sysconfig->getDisplayValue(Display::Name::Parallel)); + + // Disable screenshot navigation buttons by default + ui->screenshotNext->setEnabled(false); + ui->screenshotPrevious->setEnabled(false); + ui->screenshotNextTB->setEnabled(false); + ui->screenshotPreviousTB->setEnabled(false); + + // Different actions are taken depending on the existence and number of screenshots + screenshots = passed_sysconfig->getScreenshots(); + if (!screenshots.empty()) { + ui->screenshot->setFrameStyle(QFrame::NoFrame); + ui->screenshot->setEnabled(true); + if(screenshots.size() > 1) { + ui->screenshotNext->setEnabled(true); + ui->screenshotPrevious->setEnabled(true); + ui->screenshotNextTB->setEnabled(true); + ui->screenshotPreviousTB->setEnabled(true); + } +#ifdef Q_OS_WINDOWS + ui->screenshot->setStyleSheet(""); +#endif + if(QFileInfo::exists(screenshots.last().filePath())) { + screenshotIndex = screenshots.size() - 1; + const QPixmap pic(screenshots.at(screenshotIndex).filePath()); + ui->screenshot->setPixmap(pic.scaled(240, 160, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + } + } else { + ui->screenshotNext->setEnabled(false); + ui->screenshotPrevious->setEnabled(false); + ui->screenshotNextTB->setEnabled(false); + ui->screenshotPreviousTB->setEnabled(false); + ui->screenshot->setPixmap(QString()); + ui->screenshot->setFixedSize(240, 160); + ui->screenshot->setFrameStyle(QFrame::Box | QFrame::Sunken); + ui->screenshot->setText(tr("No screenshot")); + ui->screenshot->setEnabled(false); + ui->screenshot->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); +#ifdef Q_OS_WINDOWS + if (!windows_is_light_theme()) { + ui->screenshot->setStyleSheet("QLabel { border: 1px solid gray }"); + } else { + ui->screenshot->setStyleSheet(""); + } +#endif + } + + ui->systemLabel->setText(passed_sysconfig->displayName); + ui->statusLabel->setText(sysconfig->process->processId() == 0 ? + tr("Not running") : + QString("%1: PID %2").arg(tr("Running"), QString::number(sysconfig->process->processId()))); + ui->notesTextEdit->setPlainText(passed_sysconfig->notes); + ui->notesTextEdit->setEnabled(true); + + disconnect(sysconfig->process, &QProcess::stateChanged, this, &VMManagerDetails::updateProcessStatus); + connect(sysconfig->process, &QProcess::stateChanged, this, &VMManagerDetails::updateProcessStatus); + + disconnect(sysconfig, &VMManagerSystem::windowStatusChanged, this, &VMManagerDetails::updateWindowStatus); + connect(sysconfig, &VMManagerSystem::windowStatusChanged, this, &VMManagerDetails::updateWindowStatus); + + disconnect(sysconfig, &VMManagerSystem::clientProcessStatusChanged, this, &VMManagerDetails::updateProcessStatus); + connect(sysconfig, &VMManagerSystem::clientProcessStatusChanged, this, &VMManagerDetails::updateProcessStatus); + + updateProcessStatus(); +} + +void +VMManagerDetails::updateProcessStatus() { + const bool running = sysconfig->process->state() == QProcess::ProcessState::Running; + QString status_text = running ? + QString("%1: PID %2").arg(tr("Running"), QString::number(sysconfig->process->processId())) : + tr("Not running"); + status_text.append(sysconfig->window_obscured ? QString(" (%1)").arg(tr("waiting")) : ""); + ui->statusLabel->setText(status_text); + resetButton->setEnabled(running); + stopButton->setEnabled(running); + cadButton->setEnabled(running); + if(running) { + if(sysconfig->getProcessStatus() == VMManagerSystem::ProcessStatus::Running) { + startPauseButton->setIcon(QIcon(":/menuicons/qt/icons/pause.ico")); + startPauseButton->setToolTip(tr("Pause")); + } else { + startPauseButton->setIcon(QIcon(":/menuicons/qt/icons/run.ico")); + startPauseButton->setToolTip(tr("Continue")); + } + + disconnect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::pauseButtonPressed); + disconnect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::startButtonPressed); + connect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::pauseButtonPressed); + } else { + startPauseButton->setIcon(QIcon(":/menuicons/qt/icons/run.ico")); + disconnect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::pauseButtonPressed); + disconnect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::startButtonPressed); + connect(startPauseButton, &QToolButton::clicked, sysconfig, &VMManagerSystem::startButtonPressed); + startPauseButton->setToolTip(tr("Start")); + } +} + +void +VMManagerDetails::updateWindowStatus() +{ + qInfo("Window status changed: %i", sysconfig->window_obscured); + updateProcessStatus(); +} + +QWidget * +VMManagerDetails::createHorizontalLine(const int leftSpacing, const int rightSpacing) +{ + const auto container = new QWidget; + const auto hLayout = new QHBoxLayout(container); + + hLayout->addSpacing(leftSpacing); + + const auto line = new QFrame(); + line->setFrameShape(QFrame::HLine); + line->setFrameShadow(QFrame::Sunken); + + hLayout->addWidget(line); + hLayout->addSpacing(rightSpacing); + hLayout->setContentsMargins(0, 5, 0, 5); + + return container; +} + +void +VMManagerDetails::saveNotes() const +{ + sysconfig->setNotes(ui->notesTextEdit->toPlainText()); +} + +void +VMManagerDetails::nextScreenshot() +{ + screenshotIndex = (screenshotIndex + 1) % screenshots.size(); + const QPixmap pic(screenshots.at(screenshotIndex).filePath()); + ui->screenshot->setPixmap(pic.scaled(240, 160, Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +void +VMManagerDetails::previousScreenshot() +{ + screenshotIndex = screenshotIndex == 0 ? screenshots.size() - 1 : screenshotIndex - 1; + const QPixmap pic(screenshots.at(screenshotIndex).filePath()); + ui->screenshot->setPixmap(pic.scaled(240, 160, Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +bool +VMManagerDetails::eventFilter(QObject *watched, QEvent *event) +{ + if (watched->isWidgetType() && event->type() == QEvent::FocusOut) { + // Make sure it's the textedit + if (const auto *textEdit = qobject_cast(watched); textEdit) { + saveNotes(); + } + } + return QWidget::eventFilter(watched, event); +} + diff --git a/src/qt/qt_vmmanager_details.hpp b/src/qt/qt_vmmanager_details.hpp new file mode 100644 index 000000000..5d3bfa8a4 --- /dev/null +++ b/src/qt/qt_vmmanager_details.hpp @@ -0,0 +1,90 @@ +/* +* 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. +* +* Header for 86Box VM manager system details module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef QT_VMMANAGER_DETAILS_H +#define QT_VMMANAGER_DETAILS_H + +#include +#include "qt_vmmanager_system.hpp" +// #include "qt_vmmanager_details_section.hpp" +#include "qt_vmmanager_detailsection.hpp" + + +QT_BEGIN_NAMESPACE +//namespace Ui { class VMManagerDetails; class CollapseButton;} +namespace Ui { class VMManagerDetails;} +QT_END_NAMESPACE + +class VMManagerDetails : public QWidget { + Q_OBJECT + +public: + explicit VMManagerDetails(QWidget *parent = nullptr); + + ~VMManagerDetails() override; + + void updateData(VMManagerSystem *passed_sysconfig); + + void updateProcessStatus(); + + void updateWindowStatus(); +// CollapseButton *systemCollapseButton; + +private: + Ui::VMManagerDetails *ui; + VMManagerSystem *sysconfig; + + VMManagerDetailSection *systemSection; + VMManagerDetailSection *videoSection; + VMManagerDetailSection *storageSection; + VMManagerDetailSection *audioSection; + VMManagerDetailSection *networkSection; + VMManagerDetailSection *inputSection; + VMManagerDetailSection *portsSection; + + QFileInfoList screenshots; + int screenshotIndex = 0; + QSize screenshotLabelSize; + QSize screenshotThumbnailSize; + + QToolButton *startPauseButton; + QToolButton *resetButton; + QToolButton *stopButton; + QToolButton *configureButton; + QToolButton *cadButton; + + static QWidget* createHorizontalLine(int leftSpacing = 25, int rightSpacing = 25); + // QVBoxLayout *detailsLayout; +private slots: + void saveNotes() const; + void nextScreenshot(); + void previousScreenshot(); + +protected: + bool eventFilter(QObject *watched, QEvent *event) override; + +// CollapseButton *systemCollapseButton; +// QFrame *systemFrame; +// CollapseButton *displayCollapseButton; +// QFrame *displayFrame; +// CollapseButton *storageCollapseButton; +// QFrame *storageFrame; +}; + + + +#endif //QT_VMMANAGER_DETAILS_H diff --git a/src/qt/qt_vmmanager_details.ui b/src/qt/qt_vmmanager_details.ui new file mode 100644 index 000000000..9b4fbbe8b --- /dev/null +++ b/src/qt/qt_vmmanager_details.ui @@ -0,0 +1,293 @@ + + + VMManagerDetails + + + + 0 + 0 + 497 + 444 + + + + VMManagerDetails + + + + 0 + + + 0 + + + + + + 18 + + + + No Machines Found! + + + Qt::AlignCenter + + + + + + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + true + + + + + 0 + 0 + 139 + 388 + + + + + 0 + + + 12 + + + 12 + + + 12 + + + 12 + + + + + + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 240 + 160 + + + + + 240 + 160 + + + + + + + Qt::AlignCenter + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + + + false + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + ... + + + + + + + ... + + + true + + + + + + + + + + + 0 + 0 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Type some notes here + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + Qt::AlignCenter + + + + + + + + + + + + + + diff --git a/src/qt/qt_vmmanager_detailsection.cpp b/src/qt/qt_vmmanager_detailsection.cpp new file mode 100644 index 000000000..bd080e00c --- /dev/null +++ b/src/qt/qt_vmmanager_detailsection.cpp @@ -0,0 +1,308 @@ +/* +* 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. +* +* 86Box VM manager system details section module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include "qt_vmmanager_detailsection.hpp" +#include "ui_qt_vmmanager_detailsection.h" + +#include + +const QString VMManagerDetailSection::sectionSeparator = ";"; + +VMManagerDetailSection:: +VMManagerDetailSection(const QString §ionName) + : mainLayout(new QVBoxLayout()) + , buttonLayout(new QHBoxLayout()) + , frame(new QFrame()) + , ui(new Ui::DetailSection) +{ + ui->setupUi(this); + + frameGridLayout = new QGridLayout(); + // Create the collapse button, set the name and add it to the layout + collapseButton = new CollapseButton(); + setSectionName(sectionName); + ui->collapseButtonHolder->setContentsMargins(getMargins(MarginSection::ToolButton)); + + // Simple method to try and determine if light mode is enabled on the host +#ifdef Q_OS_WINDOWS + extern bool windows_is_light_theme(); + const bool lightMode = windows_is_light_theme(); +#else + const bool lightMode = QApplication::palette().window().color().value() > QApplication::palette().windowText().color().value(); +#endif + // Alternate layout + if ( lightMode) { + ui->collapseButtonHolder->setStyleSheet("background-color: palette(midlight);"); + } else { +#ifdef Q_OS_WINDOWS + ui->outerFrame->setStyleSheet("background-color: #272727;"); + ui->collapseButtonHolder->setStyleSheet("background-color: #616161;"); +#else + ui->collapseButtonHolder->setStyleSheet("background-color: palette(mid);"); +#endif + } + const auto sectionLabel = new QLabel(sectionName); + sectionLabel->setStyleSheet(sectionLabel->styleSheet().append("font-weight: bold;")); + ui->collapseButtonHolder->setContentsMargins(QMargins(3, 2, 0, 2)); + ui->collapseButtonHolder->layout()->addWidget(sectionLabel); + + // ui->collapseButtonHolder->layout()->addWidget(collapseButton); + collapseButton->setContent(ui->detailFrame); + // Horizontal line added after the section name / button + // const auto hLine = new QFrame(); + // hLine->setFrameShape(QFrame::HLine); + // hLine->setFrameShadow(QFrame::Sunken); + // hLine->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + // ui->collapseButtonHolder->layout()->addWidget(hLine); + const auto hSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + ui->collapseButtonHolder->layout()->addItem(hSpacer); + // collapseButton->setContent(frame); + // ui->sectionName->setVisible(false); + setVisible(false); +} + +VMManagerDetailSection:: +VMManagerDetailSection(const QVariant &varSectionName) : ui(new Ui::DetailSection) +{ + const auto sectionName = varSectionName.toString(); + + // Initialize even though they will get wiped out + // (to keep clang-tidy happy) + frameGridLayout = new QGridLayout(); + const auto outerFrame = new QFrame(); + // for the CSS + outerFrame->setObjectName("outer_frame"); + outerFrame->setContentsMargins(QMargins(0, 0, 0, 0)); + const auto innerFrameLayout = new QVBoxLayout(); + + outerFrame->setLayout(innerFrameLayout); + auto *outerFrameLayout = new QVBoxLayout(); + outerFrameLayout->addWidget(outerFrame); + outerFrameLayout->setContentsMargins(QMargins(0, 0, 0, 0)); + + const auto buttonWidget = new QWidget(this); + + mainLayout = new QVBoxLayout(); + buttonLayout = new QHBoxLayout(); + buttonWidget->setLayout(buttonLayout); + + collapseButton = new CollapseButton(); + setSectionName(sectionName); + buttonLayout->setContentsMargins(getMargins(MarginSection::ToolButton)); + buttonLayout->addWidget(collapseButton); + + // buttonLayout->addStretch(); + auto *hLine = new QFrame(); + hLine->setFrameShape(QFrame::HLine); + hLine->setFrameShadow(QFrame::Sunken); + hLine->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + buttonLayout->addWidget(hLine); + + mainLayout->addLayout(buttonLayout); + + frame = new QFrame(); + frame->setFrameShape(QFrame::Box); + frame->setFrameStyle(QFrame::NoFrame); + collapseButton->setContent(frame); + + mainLayout->addWidget(frame); + innerFrameLayout->addWidget(buttonWidget); + innerFrameLayout->addWidget(frame); + setLayout(outerFrameLayout); +} + +VMManagerDetailSection::~VMManagerDetailSection() += default; + +void +VMManagerDetailSection::setSectionName(const QString &name) +{ + sectionName = name; + collapseButton->setButtonText(" " + sectionName); + // Bold the section headers + collapseButton->setStyleSheet(collapseButton->styleSheet().append("font-weight: bold;")); +} + +void +VMManagerDetailSection::addSection(const QString &name, const QString &value, Display::Name displayField) +{ + const auto new_section = DetailSection { name, value}; + sections.push_back(new_section); + setSections(); +} + +void +VMManagerDetailSection::setupMainLayout() +{ + // clang-tidy says I don't need to check before deleting + delete mainLayout; + mainLayout = new QVBoxLayout; +} +void +VMManagerDetailSection::clearContentsSetupGrid() +{ + // Clear everything out + if(frameGridLayout) { + while(frameGridLayout->count()) { + QLayoutItem * cur_item = frameGridLayout->takeAt(0); + if(cur_item->widget()) + delete cur_item->widget(); + delete cur_item; + } + } + + delete frameGridLayout; + frameGridLayout = new QGridLayout(); + qint32 *left = nullptr, *top = nullptr, *right = nullptr, *bottom = nullptr; + frameGridLayout->getContentsMargins(left, top, right, bottom); + frameGridLayout->setContentsMargins(getMargins(MarginSection::DisplayGrid)); + ui->detailFrame->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + ui->detailFrame->setLayout(frameGridLayout); +} +void +VMManagerDetailSection::setSections() +{ + clearContentsSetupGrid(); + int row = 0; + + + for ( const auto& section : sections) { + // if the string contains the separator (defined elsewhere) then split and + // add each entry on a new line. Otherwise, just add the one. + QStringList sectionsToAdd; + if(section.value.contains(sectionSeparator)) { + sectionsToAdd = section.value.split(sectionSeparator); + } else { + sectionsToAdd.push_back(section.value); + } + bool keyAdded = false; + for(const auto&line : sectionsToAdd) { + if(line.isEmpty()) { + // Don't bother adding entries if the values are blank + continue; + } + const auto labelKey = new QLabel(); + labelKey->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + const auto labelValue = new QLabel(); + labelKey->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + labelValue->setTextInteractionFlags(labelValue->textInteractionFlags() | Qt::TextSelectableByMouse); + labelKey->setTextInteractionFlags(labelValue->textInteractionFlags() | Qt::TextSelectableByMouse); + + // Reduce the text size for the label + // First, get the existing font + auto smaller_font = labelValue->font(); + // Get a smaller size + // Not sure if I like the smaller size, back to regular for now + // auto smaller_size = 0.85 * smaller_font.pointSize(); + const auto smaller_size = 1 * smaller_font.pointSize(); + // Set the font to the smaller size + smaller_font.setPointSizeF(smaller_size); + // Assign that new, smaller font to the label + labelKey->setFont(smaller_font); + labelValue->setFont(smaller_font); + + labelKey->setText(section.name + ":"); + labelValue->setText(line); + if(!keyAdded) { + frameGridLayout->addWidget(labelKey, row, 0, Qt::AlignLeft); + keyAdded = true; + } + frameGridLayout->addWidget(labelValue, row, 1, Qt::AlignLeft); + const auto hSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum); + frameGridLayout->addItem(hSpacer, row, 2); + row++; + } + } + collapseButton->setContent(ui->detailFrame); + if (sections.size()) + setVisible(true); +} +void +VMManagerDetailSection::clear() +{ + sections.clear(); + setVisible(false); +} + +// QT for Linux and Windows doesn't have the same default margins as QT on MacOS. +// For consistency in appearance we'll have to return the margins on a per-OS basis +QMargins +VMManagerDetailSection::getMargins(const MarginSection section) +{ + switch (section) { + case MarginSection::ToolButton: +#if defined(Q_OS_WINDOWS) or defined(Q_OS_LINUX) + return {10, 0, 5, 0}; +#else + return {0, 0, 5, 0}; +#endif + case MarginSection::DisplayGrid: +#if defined(Q_OS_WINDOWS) or defined(Q_OS_LINUX) + return {10, 0, 0, 10}; +#else + return {0, 0, 0, 10}; +#endif + default: + return {}; + } +} + +// CollapseButton Class + +CollapseButton::CollapseButton(QWidget *parent) : QToolButton(parent), content_(nullptr) { + setCheckable(true); + setStyleSheet("background:none; border:none;"); + setIconSize(QSize(8, 8)); + setFont(QApplication::font()); + setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + connect(this, &QToolButton::toggled, [=](const bool checked) { + setArrowType(checked ? Qt::ArrowType::DownArrow : Qt::ArrowType::RightArrow); + content_ != nullptr && checked ? showContent() : hideContent(); + }); + setChecked(true); +} + +void CollapseButton::setButtonText(const QString &text) { + setText(" " + text); +} + +void CollapseButton::setContent(QWidget *content) { + assert(content != nullptr); + content_ = content; + const auto animation_ = new QPropertyAnimation(content_, "maximumHeight"); // QObject with auto delete + animation_->setStartValue(0); + animation_->setEasingCurve(QEasingCurve::InOutQuad); + animation_->setDuration(300); + animation_->setEndValue(content->geometry().height() + 50); + // qDebug() << "section" << text() << "has a height of" << content->geometry().height(); + animator_.clear(); + animator_.addAnimation(animation_); + if (!isChecked()) { + content->setMaximumHeight(0); + } +} + +void CollapseButton::hideContent() { + animator_.setDirection(QAbstractAnimation::Backward); + animator_.start(); +} + +void CollapseButton::showContent() { + animator_.setDirection(QAbstractAnimation::Forward); + animator_.start(); +} + diff --git a/src/qt/qt_vmmanager_detailsection.hpp b/src/qt/qt_vmmanager_detailsection.hpp new file mode 100644 index 000000000..2eb63685a --- /dev/null +++ b/src/qt/qt_vmmanager_detailsection.hpp @@ -0,0 +1,101 @@ +/* +* 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. +* +* 86Box VM manager system details section module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed + */ + +#ifndef QT_VMMANAGER_DETAILSECTION_H +#define QT_VMMANAGER_DETAILSECTION_H + +#include +#include +#include +#include +#include +#include +#include "qt_vmmanager_system.hpp" + +QT_BEGIN_NAMESPACE +namespace Ui { class DetailSection; } +QT_END_NAMESPACE + +class CollapseButton final : public QToolButton { + Q_OBJECT + +public: + explicit CollapseButton(QWidget *parent = nullptr); + + void setButtonText(const QString &text); + + void setContent(QWidget *content); + + void hideContent(); + + void showContent(); + +private: + QWidget *content_; + QString text_; + QParallelAnimationGroup animator_; +}; + +class VMManagerDetailSection final : public QWidget { + Q_OBJECT + +public: + explicit VMManagerDetailSection(const QString §ionName); + explicit VMManagerDetailSection(const QVariant &varSectionName); + // explicit VMManagerDetailSection(); + + ~VMManagerDetailSection() override; + + void addSection(const QString &name, const QString &value, Display::Name displayField = Display::Name::Unknown); + void clear(); + + CollapseButton *collapseButton; +// QGridLayout *buttonGridLayout; + QGridLayout *frameGridLayout; + QVBoxLayout *mainLayout; + QHBoxLayout *buttonLayout; + QFrame *frame; + + static const QString sectionSeparator; + + +private: + enum class MarginSection { + ToolButton, + DisplayGrid, + }; + + void setSectionName(const QString &name); + void setupMainLayout(); + void clearContentsSetupGrid(); + void setSections(); + + static QMargins getMargins(MarginSection section); + + QString sectionName; + + struct DetailSection { + QString name; + QString value; + }; + + QVector sections; + Ui::DetailSection *ui; + +}; + +#endif // QT_VMMANAGER_DETAILSECTION_H diff --git a/src/qt/qt_vmmanager_detailsection.ui b/src/qt/qt_vmmanager_detailsection.ui new file mode 100644 index 000000000..18e89ee65 --- /dev/null +++ b/src/qt/qt_vmmanager_detailsection.ui @@ -0,0 +1,91 @@ + + + DetailSection + + + + 0 + 0 + 348 + 151 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + + + + + + + + diff --git a/src/qt/qt_vmmanager_listviewdelegate.cpp b/src/qt/qt_vmmanager_listviewdelegate.cpp new file mode 100644 index 000000000..28820a044 --- /dev/null +++ b/src/qt/qt_vmmanager_listviewdelegate.cpp @@ -0,0 +1,249 @@ +/* +* 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. +* +* 86Box VM manager list view delegate module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + + +#include + +#include "qt_vmmanager_listviewdelegate.hpp" +#include "qt_vmmanager_model.hpp" + +#ifdef Q_OS_WINDOWS +extern bool windows_is_light_theme(); +#endif + + +// Thanks to scopchanov https://github.com/scopchanov/SO-MessageLog +// from https://stackoverflow.com/questions/53105343/is-it-possible-to-add-a-custom-widget-into-a-qlistview + + +VMManagerListViewDelegate::VMManagerListViewDelegate(QObject *parent) + : QStyledItemDelegate(parent), + m_ptr(new VMManagerListViewDelegateStyle) +{ +} + +VMManagerListViewDelegate::~VMManagerListViewDelegate() += default; + +void VMManagerListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const { + bool windows_light_mode = true; +#ifdef Q_OS_WINDOWS + windows_light_mode = windows_is_light_theme(); +#endif + QStyleOptionViewItem opt(option); + initStyleOption(&opt, index); + const QPalette &palette(opt.palette); + // opt.rect = opt.rect.adjusted(0, 0, 0, 20); + const QRect &rect(opt.rect); + const QRect &contentRect(rect.adjusted(m_ptr->margins.left(), + m_ptr->margins.top(), + -m_ptr->margins.right(), + -m_ptr->margins.bottom())); + + // The status icon represents the current state of the vm. Initially set to a default state. + QIcon status_icon = QApplication::style()->standardIcon(QStyle::SP_MediaStop); + auto process_variant = index.data(VMManagerModel::Roles::ProcessStatus); + auto process_status = process_variant.value(); + // The main icon, configurable. Falls back to default if it cannot be loaded. + auto customIcom = index.data(VMManagerModel::Roles::Icon).toString(); + opt.icon = QIcon(":/settings/qt/icons/86Box-gray.ico"); + if(!customIcom.isEmpty()) { + if (const auto customPixmap = QPixmap(customIcom); !customPixmap.isNull()) { + opt.icon = customPixmap; + } + } + // opt.icon = QIcon(":/settings/qt/icons/86Box-gray.ico"); + + // Set the status icon based on the process status + switch(process_status) { + case VMManagerSystem::ProcessStatus::Running: + status_icon = QIcon(":/menuicons/qt/icons/run.ico"); + break; + case VMManagerSystem::ProcessStatus::Stopped: + status_icon = QIcon(":/menuicons/qt/icons/acpi_shutdown.ico"); + break; + case VMManagerSystem::ProcessStatus::PausedWaiting: + case VMManagerSystem::ProcessStatus::RunningWaiting: + case VMManagerSystem::ProcessStatus::Paused: + status_icon = QIcon(":/menuicons/qt/icons/pause.ico"); + break; + default: + status_icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion); + } + + + // Used to determine if the horizontal separator should be drawn + const bool lastIndex = (index.model()->rowCount() - 1) == index.row(); + const bool hasIcon = !opt.icon.isNull(); + const int bottomEdge = rect.bottom(); + QFont f(opt.font); + + f.setPointSizeF(m_ptr->statusFontPointSize(opt.font)); + + painter->save(); + painter->setClipping(true); + painter->setClipRect(rect); + painter->setFont(opt.font); + + // Draw the background + if (opt.state & QStyle::State_Selected) { + // When selected, only draw the highlighted part until the horizontal separator + int offset = 2; + auto highlightRect = rect.adjusted(0, 0, 0, -offset); + painter->fillRect(highlightRect, windows_light_mode ? palette.highlight().color() : QColor("#616161")); + // Then fill the remainder with the normal color + auto regularRect = rect.adjusted(0, rect.height()-offset, 0, 0); + painter->fillRect(regularRect, windows_light_mode ? palette.light().color() : QColor("#272727")); + } else { + // Otherwise just draw the background color as usual + painter->fillRect(rect, windows_light_mode ? palette.light().color() : QColor("#272727")); + } + + // Draw bottom line. Last line gets a different color + painter->setPen(lastIndex ? palette.dark().color() + : palette.mid().color()); + painter->drawLine(lastIndex ? rect.left() : m_ptr->margins.left(), + bottomEdge, rect.right(), bottomEdge); + + // Draw system icon + if (hasIcon) { + painter->drawPixmap(contentRect.left(), contentRect.top(), + opt.icon.pixmap(m_ptr->iconSize)); + } + + // System name + QRect systemNameRect(m_ptr->systemNameBox(opt, index)); + + systemNameRect.moveTo(m_ptr->margins.left() + m_ptr->iconSize.width() + + m_ptr->spacingHorizontal, contentRect.top()); + // If desired, font can be changed here +// painter->setFont(f); + painter->setFont(opt.font); + painter->setPen(palette.text().color()); + painter->drawText(systemNameRect, Qt::TextSingleLine, opt.text); + + // Draw status icon + painter->drawPixmap(systemNameRect.left(), systemNameRect.bottom() + + m_ptr->spacingVertical, + status_icon.pixmap(m_ptr->smallIconSize)); + + // This rectangle is around the status icon + // auto point = QPoint(systemNameRect.left(), systemNameRect.bottom() + // + m_ptr->spacingVertical); + // auto point2 = QPoint(point.x() + m_ptr->smallIconSize.width(), point.y() + m_ptr->smallIconSize.height()); + // auto arect = QRect(point, point2); + // painter->drawRect(arect); + + // Draw status text + QRect statusRect(m_ptr->statusBox(opt, index)); + int extraaa = 2; + statusRect.moveTo(systemNameRect.left() + m_ptr->margins.left() + m_ptr->smallIconSize.width(), + systemNameRect.bottom() + m_ptr->spacingVertical + extraaa + (m_ptr->smallIconSize.height() - systemNameRect.height() )); + +// painter->setFont(opt.font); + painter->setFont(f); + painter->setPen(palette.windowText().color()); + painter->drawText(statusRect, Qt::TextSingleLine, + index.data(VMManagerModel::Roles::ProcessStatusString).toString()); + + painter->restore(); + +} + +QMargins VMManagerListViewDelegate::contentsMargins() const +{ + return m_ptr->margins; +} + +void VMManagerListViewDelegate::setContentsMargins(const int left, const int top, const int right, const int bottom) const +{ + m_ptr->margins = QMargins(left, top, right, bottom); +} + +int VMManagerListViewDelegate::horizontalSpacing() const +{ + return m_ptr->spacingHorizontal; +} + +void VMManagerListViewDelegate::setHorizontalSpacing(const int spacing) const +{ + m_ptr->spacingHorizontal = spacing; +} + +int VMManagerListViewDelegate::verticalSpacing() const +{ + return m_ptr->spacingVertical; +} + +void VMManagerListViewDelegate::setVerticalSpacing(const int spacing) const +{ + m_ptr->spacingVertical = spacing; +} + + +QSize VMManagerListViewDelegate::sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItem opt(option); + initStyleOption(&opt, index); + + const int textHeight = m_ptr->systemNameBox(opt, index).height() + + m_ptr->spacingVertical + m_ptr->statusBox(opt, index).height(); + const int iconHeight = m_ptr->iconSize.height(); + const int h = textHeight > iconHeight ? textHeight : iconHeight; + + // return the same width + // for height, add margins on top and bottom *plus* either the text or icon height, whichever is greater + // Note: text height is the combined value of the system name and the status just below the name + return {opt.rect.width(), m_ptr->margins.top() + h + + m_ptr->margins.bottom()}; +} + +VMManagerListViewDelegateStyle::VMManagerListViewDelegateStyle() : + iconSize(32, 32), + smallIconSize(16, 16), + // bottom gets a little more than the top because of the custom separator + margins(4, 10, 8, 12), + // Spacing between icon and text + spacingHorizontal(8), + spacingVertical(4) +{ + +} + +QRect VMManagerListViewDelegateStyle::statusBox(const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QFont f(option.font); + + f.setPointSizeF(statusFontPointSize(option.font)); + + return QFontMetrics(f).boundingRect(index.data(VMManagerModel::Roles::ProcessStatusString).toString()) + .adjusted(0, 0, 1, 1); +} + +qreal VMManagerListViewDelegateStyle::statusFontPointSize(const QFont &f) const +{ + return 0.75*f.pointSize(); +// return 1*f.pointSize(); +} + +QRect VMManagerListViewDelegateStyle::systemNameBox(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + return option.fontMetrics.boundingRect(option.text).adjusted(0, 0, 1, 1); +} diff --git a/src/qt/qt_vmmanager_listviewdelegate.hpp b/src/qt/qt_vmmanager_listviewdelegate.hpp new file mode 100644 index 000000000..84325086d --- /dev/null +++ b/src/qt/qt_vmmanager_listviewdelegate.hpp @@ -0,0 +1,67 @@ +/* +* 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. +* +* Header for 86Box VM manager list view delegate module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef QT_VMMANAGER_LISTVIEWDELEGATE_H +#define QT_VMMANAGER_LISTVIEWDELEGATE_H + +#include +#include +#include "qt_vmmanager_system.hpp" + +class VMManagerListViewDelegateStyle +{ + VMManagerListViewDelegateStyle(); + + [[nodiscard]] inline QRect systemNameBox(const QStyleOptionViewItem &option, + const QModelIndex &index) const; + [[nodiscard]] inline qreal statusFontPointSize(const QFont &f) const; + [[nodiscard]] inline QRect statusBox(const QStyleOptionViewItem &option, const QModelIndex &index) const; + + QSize iconSize; + QSize smallIconSize; + QMargins margins; + int spacingHorizontal; + int spacingVertical; + + friend class VMManagerListViewDelegate; +}; + +class VMManagerListViewDelegate final : public QStyledItemDelegate { + Q_OBJECT + +public: + explicit VMManagerListViewDelegate(QObject *parent = nullptr); + ~VMManagerListViewDelegate() override; + using QStyledItemDelegate::QStyledItemDelegate; + + [[nodiscard]] QMargins contentsMargins() const; + void setContentsMargins(int left, int top, int right, int bottom) const; + + [[nodiscard]] int horizontalSpacing() const; + void setHorizontalSpacing(int spacing) const; + + [[nodiscard]] int verticalSpacing() const; + void setVerticalSpacing(int spacing) const; + + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + [[nodiscard]] QSize sizeHint(const QStyleOptionViewItem &option, + const QModelIndex &index) const override; +private: + VMManagerListViewDelegateStyle *m_ptr; +}; +#endif // QT_VMMANAGER_LISTVIEWDELEGATE_H \ No newline at end of file diff --git a/src/qt/qt_vmmanager_main.cpp b/src/qt/qt_vmmanager_main.cpp new file mode 100644 index 000000000..8c83b549f --- /dev/null +++ b/src/qt/qt_vmmanager_main.cpp @@ -0,0 +1,521 @@ +/* +* 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. +* +* 86Box VM manager main module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qt_vmmanager_main.hpp" +#include "ui_qt_vmmanager_main.h" +#include "qt_vmmanager_model.hpp" +#include "qt_vmmanager_addmachine.hpp" + +VMManagerMain::VMManagerMain(QWidget *parent) : + QWidget(parent), ui(new Ui::VMManagerMain), selected_sysconfig(new VMManagerSystem) { + ui->setupUi(this); + this->setWindowTitle("86Box VM Manager"); + + // Set up the main listView + ui->listView->setItemDelegate(new VMManagerListViewDelegate); + vm_model = new VMManagerModel; + proxy_model = new StringListProxyModel(this); + proxy_model->setSourceModel(vm_model); + ui->listView->setModel(proxy_model); + proxy_model->setSortCaseSensitivity(Qt::CaseInsensitive); + ui->listView->model()->sort(0, Qt::AscendingOrder); + + // Connect the model signal + connect(vm_model, &VMManagerModel::systemDataChanged, this, &VMManagerMain::modelDataChange); + + // Set up the context menu for the list view + ui->listView->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->listView, &QListView::customContextMenuRequested, [this](const QPoint &pos) { + const auto indexAt = ui->listView->indexAt(pos); + if (indexAt.isValid()) { + QMenu contextMenu(tr("Context Menu"), ui->listView); + + QAction nameChangeAction(tr("Change display name")); + contextMenu.addAction(&nameChangeAction); + // Use a lambda to call a function so indexAt can be passed + connect(&nameChangeAction, &QAction::triggered, ui->listView, [this, indexAt] { + updateDisplayName(indexAt); + }); + + QAction openSystemFolderAction(tr("Open folder")); + contextMenu.addAction(&openSystemFolderAction); + connect(&openSystemFolderAction, &QAction::triggered, [this, indexAt] { + if (const auto configDir = indexAt.data(VMManagerModel::Roles::ConfigDir).toString(); !configDir.isEmpty()) { + QDir dir(configDir); + if (!dir.exists()) + dir.mkpath("."); + + QDesktopServices::openUrl(QUrl(QString("file:///") + dir.canonicalPath())); + } + }); + + QAction convertToP3(tr("Convert system to PIII")); + contextMenu.addAction(&convertToP3); + convertToP3.setEnabled(false); + + QAction setSystemIcon(tr("Set icon")); + contextMenu.addAction(&setSystemIcon); + connect(&setSystemIcon, &QAction::triggered, [this, indexAt] { + IconSelectionDialog dialog(":/systemicons/"); + if(dialog.exec() == QDialog::Accepted) { + const QString iconName = dialog.getSelectedIconName(); + // A Blank iconName will cause setIcon to reset to the default + selected_sysconfig->setIcon(iconName); + } + }); + + contextMenu.addSeparator(); + + QAction showRawConfigFile(tr("Show config file")); + contextMenu.addAction(&showRawConfigFile); + connect(&showRawConfigFile, &QAction::triggered, [this, indexAt] { + if (const auto configFile = indexAt.data(VMManagerModel::Roles::ConfigFile).toString(); !configFile.isEmpty()) { + showTextFileContents(indexAt.data(Qt::DisplayRole).toString(), configFile); + } + }); + + contextMenu.exec(ui->listView->viewport()->mapToGlobal(pos)); + } + }); + + // Initial default details view + vm_details = new VMManagerDetails(); + ui->detailsArea->layout()->addWidget(vm_details); + const QItemSelectionModel *selection_model = ui->listView->selectionModel(); + + connect(selection_model, &QItemSelectionModel::currentChanged, this, &VMManagerMain::currentSelectionChanged); + // If there are items in the model, make sure to select the first item by default. + // When settings are loaded, the last selected item will be selected (if available) + if (proxy_model->rowCount(QModelIndex()) > 0) { + const QModelIndex first_index = proxy_model->index(0, 0); + ui->listView->setCurrentIndex(first_index); + } + + // Load and apply settings + loadSettings(); + + // Set up search bar + connect(ui->searchBar, &QLineEdit::textChanged, this, &VMManagerMain::searchSystems); + // Create the completer + auto *completer = new QCompleter(this); + completer->setCaseSensitivity(Qt::CaseInsensitive); + completer->setFilterMode(Qt::MatchContains); + // Get the completer list + const auto allStrings = getSearchCompletionList(); + // Set up the completer + auto *completerModel = new QStringListModel(allStrings, completer); + completer->setModel(completerModel); + ui->searchBar->setCompleter(completer); + + // Set initial status bar after the event loop starts + QTimer::singleShot(0, this, [this] { + emit updateStatusRight(totalCountString()); + }); + + // Start update check after a slight delay + QTimer::singleShot(1000, this, [this] { + if(updateCheck) { + backgroundUpdateCheckStart(); + } + }); +} + +VMManagerMain::~VMManagerMain() { + delete ui; + delete vm_model; +} + +void +VMManagerMain::currentSelectionChanged(const QModelIndex ¤t, + const QModelIndex &previous) +{ + if(!current.isValid()) { + return; + } + + const auto mapped_index = proxy_model->mapToSource(current); + selected_sysconfig = vm_model->getConfigObjectForIndex(mapped_index); + vm_details->updateData(selected_sysconfig); + + // Emit that the selection changed, include with the process state + emit selectionChanged(current, selected_sysconfig->process->state()); + +} + +void +VMManagerMain::settingsButtonPressed() { + if(!currentSelectionIsValid()) { + return; + } + selected_sysconfig->launchSettings(); + // If the process is already running, the system will be instructed to open its settings window. + // Otherwise the process will be launched and will need to be tracked here. + if (!selected_sysconfig->isProcessRunning()) { + connect(selected_sysconfig->process, QOverload::of(&QProcess::finished), + [=](const int exitCode, const QProcess::ExitStatus exitStatus){ + if (exitCode != 0 || exitStatus != QProcess::NormalExit) { + qInfo().nospace().noquote() << "Abnormal program termination while launching settings: exit code " << exitCode << ", exit status " << exitStatus; + return; + } + selected_sysconfig->reloadConfig(); + vm_details->updateData(selected_sysconfig); + }); + } +} + +void +VMManagerMain::startButtonPressed() const +{ + if(!currentSelectionIsValid()) { + return; + } + selected_sysconfig->startButtonPressed(); +} + +void +VMManagerMain::restartButtonPressed() const +{ + if(!currentSelectionIsValid()) { + return; + } + selected_sysconfig->restartButtonPressed(); + +} + +void +VMManagerMain::pauseButtonPressed() const +{ + if(!currentSelectionIsValid()) { + return; + } + selected_sysconfig->pauseButtonPressed(); +} + +void +VMManagerMain::shutdownRequestButtonPressed() const +{ + if (!currentSelectionIsValid()) { + return; + } + selected_sysconfig->shutdownRequestButtonPressed(); +} + +void +VMManagerMain::shutdownForceButtonPressed() const +{ + if (!currentSelectionIsValid()) { + return; + } + selected_sysconfig->shutdownForceButtonPressed(); +} + +// This function doesn't appear to be needed any longer +void +VMManagerMain::refresh() +{ + const auto current_index = ui->listView->currentIndex(); + emit selectionChanged(current_index, selected_sysconfig->process->state()); + + // if(!selected_sysconfig->config_file.path().isEmpty()) { + if(!selected_sysconfig->isValid()) { + // what was happening here? + } +} + +void +VMManagerMain::updateDisplayName(const QModelIndex &index) +{ + QDialog dialog; + dialog.setMinimumWidth(400); + dialog.setWindowTitle(tr("Set display name")); + const auto layout = new QVBoxLayout(&dialog); + const auto label = new QLabel(tr("Enter the new display name (blank to reset)")); + label->setAlignment(Qt::AlignHCenter); + label->setContentsMargins(QMargins(0, 0, 0, 5)); + layout->addWidget(label); + const auto lineEdit = new QLineEdit(index.data().toString(), &dialog); + layout->addWidget(lineEdit); + lineEdit->selectAll(); + + const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog); + layout->addWidget(buttonBox); + + connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + + if (const bool accepted = dialog.exec() == QDialog::Accepted; accepted) { + const auto mapped_index = proxy_model->mapToSource(index); + vm_model->updateDisplayName(mapped_index, lineEdit->text()); + selected_sysconfig = vm_model->getConfigObjectForIndex(mapped_index); + vm_details->updateData(selected_sysconfig); + ui->listView->scrollTo(ui->listView->currentIndex(), QAbstractItemView::PositionAtCenter); + } +} + +void +VMManagerMain::loadSettings() +{ + const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + const auto lastSelection = config->getStringValue("last_selection"); + updateCheck = config->getStringValue("update_check").toInt(); + regexSearch = config->getStringValue("regex_search").toInt(); + + const auto matches = ui->listView->model()->match(vm_model->index(0, 0), VMManagerModel::Roles::ConfigName, QVariant::fromValue(lastSelection)); + if (!matches.empty()) { + ui->listView->setCurrentIndex(matches.first()); + ui->listView->scrollTo(ui->listView->currentIndex(), QAbstractItemView::PositionAtCenter); + } +} +bool +VMManagerMain::currentSelectionIsValid() const +{ + return ui->listView->currentIndex().isValid() && selected_sysconfig->isValid(); +} + +// Used from MainWindow during app exit to obtain and persist the current selection +QString +VMManagerMain::getCurrentSelection() const +{ + return ui->listView->currentIndex().data(VMManagerModel::Roles::ConfigName).toString(); +} + +void +VMManagerMain::searchSystems(const QString &text) const +{ + // Escape the search text string unless regular expression searching is enabled. + // When escaped, the search string functions as a plain text match. + const auto searchText = regexSearch ? text : QRegularExpression::escape(text); + const QRegularExpression regex(searchText, QRegularExpression::CaseInsensitiveOption); + if (!regex.isValid()) { + qDebug() << "Skipping, invalid regex"; + return; + } + proxy_model->setFilterRegularExpression(regex); + // Searching (filtering) can cause the list view to change. If there is still a valid selection, + // make sure to scroll to it + if (ui->listView->currentIndex().isValid()) { + ui->listView->scrollTo(ui->listView->currentIndex(), QAbstractItemView::PositionAtCenter); + } +} + +void +VMManagerMain::newMachineWizard() +{ + const auto wizard = new VMManagerAddMachine(this); + if (wizard->exec() == QDialog::Accepted) { + const auto newName = wizard->field("systemName").toString(); + const auto systemDir = wizard->field("systemLocation").toString(); + const auto existingConfiguration = wizard->field("existingConfiguration").toString(); + addNewSystem(newName, systemDir, existingConfiguration); + } +} + +void +VMManagerMain::addNewSystem(const QString &name, const QString &dir, const QString &configFile) +{ + const auto newSytemDirectory = QDir(QDir::cleanPath(dir + "/" + name)); + + // qt replaces `/` with native separators + const auto newSystemConfigFile = QFileInfo(newSytemDirectory.path() + "/" + "86box.cfg"); + if (newSystemConfigFile.exists() || newSytemDirectory.exists()) { + QMessageBox::critical(this, tr("Directory in use"), tr("The selected directory is already in use. Please select a different directory.")); + return; + } + // Create the directory + const QDir qmkdir; + if (const bool mkdirResult = qmkdir.mkdir(newSytemDirectory.path()); !mkdirResult) { + QMessageBox::critical(this, tr("Create directory failed"), tr("Unable to create the directory for the new system")); + return; + } + // If specified, write the contents of the configuration file before starting + if (!configFile.isEmpty()) { + const auto configPath = newSystemConfigFile.absoluteFilePath(); + const auto file = new QFile(configPath); + if (!file->open(QIODevice::WriteOnly)) { + qWarning() << "Unable to open file " << configPath; + QMessageBox::critical(this, tr("Configuration write failed"), tr("Unable to open the configuration file at %1 for writing").arg(configPath)); + return; + } + file->write(configFile.toUtf8()); + file->flush(); + file->close(); + } + + const auto new_system = new VMManagerSystem(newSystemConfigFile.absoluteFilePath()); + new_system->launchSettings(); + // Handle this in a closure so we can capture the temporary new_system object + connect(new_system->process, QOverload::of(&QProcess::finished), + [=](const int exitCode, const QProcess::ExitStatus exitStatus) { + if (exitCode != 0 || exitStatus != QProcess::NormalExit) { + qInfo().nospace().noquote() << "Abnormal program termination while creating new system: exit code " << exitCode << ", exit status " << exitStatus; + qInfo() << "Not adding system due to errors"; + QMessageBox::critical(this, tr("Error adding system"), + tr("Abnormal program termination while creating new system: exit code %1, exit status %2.\n\nThe system will not be added.").arg(QString::number(exitCode), exitStatus)); + delete new_system; + return; + } + // Create a new QFileInfo because the info from the old one may be cached + if (const auto fi = QFileInfo(new_system->config_file.absoluteFilePath()); !fi.exists()) { + // No config file which means the cancel button was pressed in the settings dialog + // Attempt to clean up the directory that was created + const QDir qrmdir; + if (const bool result = qrmdir.rmdir(newSytemDirectory.path()); !result) { + qWarning() << "Error cleaning up the old directory for canceled operation. Continuing anyway."; + } + delete new_system; + return; + } + const auto current_index = ui->listView->currentIndex(); + vm_model->reload(this); + const auto created_object = vm_model->getIndexForConfigFile(new_system->config_file); + if (created_object.row() < 0) { + // For some reason the index of the new object couldn't be determined. Fall back to the old index. + ui->listView->setCurrentIndex(current_index); + delete new_system; + return; + } + // Get the index of the newly-created system and select it + const QModelIndex mapped_index = proxy_model->mapFromSource(created_object); + ui->listView->setCurrentIndex(mapped_index); + delete new_system; + }); +} + +QStringList +VMManagerMain::getSearchCompletionList() const +{ + QSet uniqueStrings; + for (int row = 0; row < vm_model->rowCount(QModelIndex()); ++row) { + QModelIndex index = vm_model->index(row, 0); + auto fullList = vm_model->data(index, VMManagerModel::Roles::SearchList).toStringList(); + QSet uniqueSet(fullList.begin(), fullList.end()); + uniqueStrings.unite(uniqueSet); + } + // Convert the set back to a QStringList + QStringList allStrings = uniqueStrings.values(); + return allStrings; +} + +QString +VMManagerMain::totalCountString() const +{ + const auto count = vm_model->rowCount(QModelIndex()); + return QString("%1 %2").arg(QString::number(count), tr("total")); +} + +void +VMManagerMain::modelDataChange() +{ + // Model data has changed. This includes process status. + // Update the counts / totals accordingly + auto modelStats = vm_model->getProcessStats(); + QStringList stats; + for (auto it = modelStats.constBegin(); it != modelStats.constEnd(); ++it) { + const auto &key = it.key(); + stats.append(QString("%1 %2").arg(QString::number(modelStats[key]), key)); + } + auto states = stats.join(", "); + if (!modelStats.isEmpty()) { + states.append(", "); + } + + emit updateStatusRight(states + totalCountString()); +} + +void +VMManagerMain::onPreferencesUpdated() +{ + // Only reload values that we care about + const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + const auto oldRegexSearch = regexSearch; + regexSearch = config->getStringValue("regex_search").toInt(); + if (oldRegexSearch != regexSearch) { + ui->searchBar->clear(); + } +} + +void +VMManagerMain::backgroundUpdateCheckStart() const +{ + auto updateChannel = UpdateCheck::UpdateChannel::CI; +#ifdef RELEASE_BUILD + updateChannel = UpdateCheck::UpdateChannel::Stable; +#endif + const auto updateCheck = new UpdateCheck(updateChannel); + connect(updateCheck, &UpdateCheck::updateCheckComplete, this, &VMManagerMain::backgroundUpdateCheckComplete); + connect(updateCheck, &UpdateCheck::updateCheckError, this, &VMManagerMain::backgroundUpdateCheckError); + updateCheck->checkForUpdates(); +} + +void +VMManagerMain::backgroundUpdateCheckComplete(const UpdateCheck::UpdateResult &result) +{ + qDebug() << "Check complete: update available?" << result.updateAvailable; + auto type = result.channel == UpdateCheck::UpdateChannel::CI ? tr("Build") : tr("Version"); + const auto updateMessage = QString("%1: %2 %3").arg( tr("An update to 86Box is available"), type, result.latestVersion); + emit updateStatusLeft(updateMessage); +} + +void +VMManagerMain::backgroundUpdateCheckError(const QString &errorMsg) +{ + qDebug() << "Update check failed with the following error:" << errorMsg; + // TODO: Update the status bar +} + +void +VMManagerMain::showTextFileContents(const QString &title, const QString &path) +{ + // Make sure we can open the file + const auto fi = QFileInfo(path); + if(!fi.exists()) { + qWarning("Requested file does not exist: %s", path.toUtf8().constData()); + return; + } + // Read the file + QFile displayFile(path); + if (!displayFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + qWarning("Couldn't open the file: error %d", displayFile.error()); + return; + } + const QString configFileContents = displayFile.readAll(); + displayFile.close(); + + const auto textDisplayDialog = new QDialog(this); + textDisplayDialog->setFixedSize(QSize(540, 360)); + textDisplayDialog->setWindowTitle(QString("%1 - %2").arg(title, fi.fileName())); + + const auto textEdit = new QPlainTextEdit(); + textEdit->setReadOnly(true); + textEdit->setPlainText(configFileContents); + const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok); + connect(buttonBox, &QDialogButtonBox::accepted, textDisplayDialog, &QDialog::accept); + const auto layout = new QVBoxLayout(); + textDisplayDialog->setLayout(layout); + textDisplayDialog->layout()->addWidget(textEdit); + textDisplayDialog->layout()->addWidget(buttonBox); + textDisplayDialog->exec(); +} diff --git a/src/qt/qt_vmmanager_main.hpp b/src/qt/qt_vmmanager_main.hpp new file mode 100644 index 000000000..c3c541b4f --- /dev/null +++ b/src/qt/qt_vmmanager_main.hpp @@ -0,0 +1,167 @@ +/* +* 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. +* +* Header for 86Box VM manager main module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef QT_VMMANAGER_MAIN_H +#define QT_VMMANAGER_MAIN_H + +#include "qt_updatecheck.hpp" + +#include +#include "qt_vmmanager_model.hpp" +#include "qt_vmmanager_details.hpp" +#include "qt_vmmanager_listviewdelegate.hpp" + +#include + +extern "C" { +#include <86box/86box.h> // for vmm_path +} + + +QT_BEGIN_NAMESPACE +namespace Ui { class VMManagerMain; } +QT_END_NAMESPACE + +class VMManagerMain final : public QWidget { + Q_OBJECT + +public: + explicit VMManagerMain(QWidget *parent = nullptr); + ~VMManagerMain() override; + // Used to save the current selection + [[nodiscard]] QString getCurrentSelection() const; + + enum class ToolbarButton { + Start, + Pause, + StartPause, + Shutdown, + Reset, + CtrlAltDel, + Settings, + }; +signals: + void selectionChanged(const QModelIndex ¤tSelection, QProcess::ProcessState processState); + void updateStatusLeft(const QString &text); + void updateStatusRight(const QString &text); + +public slots: + void startButtonPressed() const; + void settingsButtonPressed(); + void restartButtonPressed() const; + void pauseButtonPressed() const; + void shutdownRequestButtonPressed() const; + void shutdownForceButtonPressed() const; + void searchSystems(const QString &text) const; + void newMachineWizard(); + void addNewSystem(const QString &name, const QString &dir, const QString &configFile = {}); + [[nodiscard]] QStringList getSearchCompletionList() const; + void modelDataChange(); + void onPreferencesUpdated(); + +private: + Ui::VMManagerMain *ui; + + VMManagerModel *vm_model; + VMManagerDetails *vm_details; + VMManagerSystem *selected_sysconfig; + // VMManagerConfig *config; + QSortFilterProxyModel *proxy_model; + bool updateCheck = false; + bool regexSearch = false; + + // void updateSelection(const QItemSelection &selected, + // const QItemSelection &deselected); + void currentSelectionChanged(const QModelIndex ¤t, + const QModelIndex &previous); + void refresh(); + void updateDisplayName(const QModelIndex &index); + void loadSettings(); + [[nodiscard]] bool currentSelectionIsValid() const; + [[nodiscard]] QString totalCountString() const; + void backgroundUpdateCheckStart() const; + void showTextFileContents(const QString &title, const QString &path); +private slots: + void backgroundUpdateCheckComplete(const UpdateCheck::UpdateResult &result); + void backgroundUpdateCheckError(const QString &errorMsg); +}; + +#include +#include +#include +#include + +class IconSelectionDialog final : public QDialog { + Q_OBJECT + +public: + explicit IconSelectionDialog(QString assetPath, QWidget *parent = nullptr) : QDialog(parent), listWidget(new QListWidget) { + // Set the list widget to icon mode + listWidget->setViewMode(QListWidget::IconMode); + setFixedSize(QSize(540, 360)); + listWidget->setGridSize(QSize(96, 96)); + listWidget->setIconSize(QSize(64, 64)); + // Read in all the assets from the given path + const QDir iconsDir(assetPath); + if (!assetPath.endsWith("/")) { + assetPath.append("/"); + } + setWindowTitle(tr("Select an icon")); + + // Loop on all files and add them as items (icons) in QListWidget + for(const QString& iconName : iconsDir.entryList()) { + const auto item = new QListWidgetItem(QIcon(assetPath + iconName), iconName); + // Set the UserRole to the resource bundle path + item->setData(Qt::UserRole, assetPath + iconName); + listWidget->addItem(item); + } + + // Dialog buttons + const auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Reset); + // Use the reset button for resetting the icon to the default + const QPushButton* resetButton = buttonBox->button(QDialogButtonBox::Reset); + + // Connect the buttons signals + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + connect(listWidget, &QListWidget::doubleClicked, this, &QDialog::accept); + connect(resetButton, &QPushButton::clicked, [this] { + // For reset, set the index to invalid so the caller will receive a blank string + listWidget->setCurrentIndex(QModelIndex()); + // Then accept + QDialog::accept(); + }); + + const auto layout = new QVBoxLayout(this); + layout->addWidget(listWidget); + layout->addWidget(buttonBox); + } + + public slots: + [[nodiscard]] QString getSelectedIconName() const { + if (listWidget->currentIndex().isValid()) { + return listWidget->currentItem()->data(Qt::UserRole).toString(); + } + // Index is invalid because the reset button was pressed + return {}; + } + +private: + QListWidget* listWidget; +}; + +#endif //QT_VMMANAGER_MAIN_H diff --git a/src/qt/qt_vmmanager_main.ui b/src/qt/qt_vmmanager_main.ui new file mode 100644 index 000000000..c19094345 --- /dev/null +++ b/src/qt/qt_vmmanager_main.ui @@ -0,0 +1,119 @@ + + + VMManagerMain + + + + 0 + 0 + 815 + 472 + + + + + 0 + 0 + + + + VMManagerMain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 200 + 0 + + + + + 200 + 16777215 + + + + + + + + Qt::ClickFocus + + + Search + + + true + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + diff --git a/src/qt/qt_vmmanager_mainwindow.cpp b/src/qt/qt_vmmanager_mainwindow.cpp new file mode 100644 index 000000000..767bbcef2 --- /dev/null +++ b/src/qt/qt_vmmanager_mainwindow.cpp @@ -0,0 +1,178 @@ +/* +* 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. +* +* 86Box VM manager main window +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include "qt_vmmanager_mainwindow.hpp" +#include "qt_vmmanager_main.hpp" +#include "qt_vmmanager_preferences.hpp" +#include "ui_qt_vmmanager_mainwindow.h" +#include "qt_updatecheckdialog.hpp" + +#include +#include +#include + +VMManagerMainWindow:: +VMManagerMainWindow(QWidget *parent) + : ui(new Ui::VMManagerMainWindow) + , vmm(new VMManagerMain(this)) + , statusLeft(new QLabel) + , statusRight(new QLabel) +{ + ui->setupUi(this); + + // Connect signals from the VMManagerMain widget + connect(vmm, &VMManagerMain::selectionChanged, this, &VMManagerMainWindow::vmmSelectionChanged); + + setWindowTitle(tr("86Box VM Manager")); + setCentralWidget(vmm); + + // Set up the buttons + connect(ui->actionStartPause, &QAction::triggered, vmm, &VMManagerMain::startButtonPressed); + connect(ui->actionSettings, &QAction::triggered, vmm, &VMManagerMain::settingsButtonPressed); + connect(ui->actionHard_Reset, &QAction::triggered, vmm, &VMManagerMain::restartButtonPressed); + connect(ui->actionForce_Shutdown, &QAction::triggered, vmm, &VMManagerMain::shutdownForceButtonPressed); + connect(ui->actionNew_Machine, &QAction::triggered, vmm, &VMManagerMain::newMachineWizard); + + // Set up menu actions + connect(ui->actionCheck_for_updates, &QAction::triggered, this, &VMManagerMainWindow::checkForUpdatesTriggered); + + // TODO: Remove all of this (all the way to END REMOVE) once certain the search will no longer be in the toolbar. + // BEGIN REMOVE + // Everything is still setup here for it but it is all hidden. None of it will be + // needed if the search stays in VMManagerMain + ui->actionStartPause->setEnabled(true); + ui->actionStartPause->setIcon(QIcon(":/menuicons/qt/icons/run.ico")); + ui->actionStartPause->setText(tr("Start")); + ui->actionStartPause->setToolTip(tr("Start")); + ui->actionHard_Reset->setEnabled(false); + ui->actionForce_Shutdown->setEnabled(false); + ui->actionCtrl_Alt_Del->setEnabled(false); + + const auto searchBar = new QLineEdit(); + searchBar->setMinimumWidth(150); + searchBar->setPlaceholderText(" " + tr("Search")); + searchBar->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Preferred); + searchBar->setClearButtonEnabled(true); + // Spacer to make the search go all the way to the right + const auto spacer = new QWidget(); + spacer->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Preferred); + ui->toolBar->addWidget(spacer); + ui->toolBar->addWidget(searchBar); + // Connect signal for search + connect(searchBar, &QLineEdit::textChanged, vmm, &VMManagerMain::searchSystems); + // Preferences + connect(ui->actionPreferences, &QAction::triggered, this, &VMManagerMainWindow::preferencesTriggered); + + // Create a completer for the search bar + auto *completer = new QCompleter(this); + completer->setCaseSensitivity(Qt::CaseInsensitive); + completer->setFilterMode(Qt::MatchContains); + // Get the completer list + const auto allStrings = vmm->getSearchCompletionList(); + // Set up the completer + auto *completerModel = new QStringListModel(allStrings, completer); + completer->setModel(completerModel); + searchBar->setCompleter(completer); + ui->toolBar->setVisible(false); + // END REMOVE + + // Status bar widgets + statusLeft->setAlignment(Qt::AlignLeft); + statusRight->setAlignment(Qt::AlignRight); + ui->statusbar->addPermanentWidget(statusLeft, 1); + ui->statusbar->addPermanentWidget(statusRight, 1); + connect(vmm, &VMManagerMain::updateStatusLeft, this, &VMManagerMainWindow::setStatusLeft); + connect(vmm, &VMManagerMain::updateStatusRight, this, &VMManagerMainWindow::setStatusRight); + + // Inform the main view when preferences are updated + connect(this, &VMManagerMainWindow::preferencesUpdated, vmm, &VMManagerMain::onPreferencesUpdated); + +} + +VMManagerMainWindow::~ +VMManagerMainWindow() + = default; + +void +VMManagerMainWindow::vmmSelectionChanged(const QModelIndex ¤tSelection, const QProcess::ProcessState processState) const +{ + if (processState == QProcess::Running) { + ui->actionStartPause->setEnabled(true); + ui->actionStartPause->setIcon(QIcon(":/menuicons/qt/icons/pause.ico")); + ui->actionStartPause->setText(tr("Pause")); + ui->actionStartPause->setToolTip(tr("Pause")); + ui->actionHard_Reset->setEnabled(true); + ui->actionForce_Shutdown->setEnabled(true); + ui->actionCtrl_Alt_Del->setEnabled(true); + } else { + ui->actionStartPause->setEnabled(true); + ui->actionStartPause->setIcon(QIcon(":/menuicons/qt/icons/run.ico")); + ui->actionStartPause->setText(tr("Start")); + ui->actionStartPause->setToolTip(tr("Start")); + ui->actionHard_Reset->setEnabled(false); + ui->actionForce_Shutdown->setEnabled(false); + ui->actionCtrl_Alt_Del->setEnabled(false); + } +} +void +VMManagerMainWindow::preferencesTriggered() +{ + const auto prefs = new VMManagerPreferences(); + if (prefs->exec() == QDialog::Accepted) { + emit preferencesUpdated(); + } +} + +void +VMManagerMainWindow::saveSettings() const +{ + const auto currentSelection = vmm->getCurrentSelection(); + const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + config->setStringValue("last_selection", currentSelection); + // Sometimes required to ensure the settings save before the app exits + config->sync(); +} + +void +VMManagerMainWindow::closeEvent(QCloseEvent *event) +{ + saveSettings(); + QMainWindow::closeEvent(event); +} + +void +VMManagerMainWindow::setStatusLeft(const QString &text) const +{ + statusLeft->setText(text); +} + +void +VMManagerMainWindow::setStatusRight(const QString &text) const +{ + statusRight->setText(text); +} + +void +VMManagerMainWindow::checkForUpdatesTriggered() +{ + auto updateChannel = UpdateCheck::UpdateChannel::CI; +#ifdef RELEASE_BUILD + updateChannel = UpdateCheck::UpdateChannel::Stable; +#endif + const auto updateCheck = new UpdateCheckDialog(updateChannel); + updateCheck->exec(); +} diff --git a/src/qt/qt_vmmanager_mainwindow.hpp b/src/qt/qt_vmmanager_mainwindow.hpp new file mode 100644 index 000000000..764ed5ef8 --- /dev/null +++ b/src/qt/qt_vmmanager_mainwindow.hpp @@ -0,0 +1,59 @@ +/* +* 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. +* +* Header for 86Box VM manager main window +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef VMM_MAINWINDOW_H +#define VMM_MAINWINDOW_H + +#include "qt_vmmanager_main.hpp" + +#include +#include +#include + +namespace Ui { +class VMManagerMainWindow; +} + +class VMManagerMainWindow final : public QMainWindow +{ + Q_OBJECT +public: + explicit VMManagerMainWindow(QWidget *parent = nullptr); + ~VMManagerMainWindow() override; +signals: + void preferencesUpdated(); + +private: + Ui::VMManagerMainWindow *ui; + VMManagerMain *vmm; + void saveSettings() const; + QLabel *statusLeft; + QLabel *statusRight; +public slots: + void setStatusLeft(const QString &text) const; + void setStatusRight(const QString &text) const; + +private slots: + void vmmSelectionChanged(const QModelIndex ¤tSelection, QProcess::ProcessState processState) const; + void preferencesTriggered(); + static void checkForUpdatesTriggered(); + +protected: + void closeEvent(QCloseEvent *event) override; +}; + +#endif // VMM_MAINWINDOW_H diff --git a/src/qt/qt_vmmanager_mainwindow.ui b/src/qt/qt_vmmanager_mainwindow.ui new file mode 100644 index 000000000..e3e0a242d --- /dev/null +++ b/src/qt/qt_vmmanager_mainwindow.ui @@ -0,0 +1,212 @@ + + + VMManagerMainWindow + + + + 0 + 0 + 900 + 600 + + + + MainWindow + + + + + + 0 + 0 + 900 + 21 + + + + + Tools + + + + + + + File + + + + + + + + + + toolBar + + + false + + + + 16 + 16 + + + + Qt::ToolButtonStyle::ToolButtonIconOnly + + + TopToolBarArea + + + false + + + + + + + + + + + Do something + + + + + true + + + + :/menuicons/qt/icons/run.ico:/menuicons/qt/icons/run.ico + + + Start + + + false + + + + + + :/menuicons/qt/icons/hard_reset.ico:/menuicons/qt/icons/hard_reset.ico + + + &Hard Reset... + + + false + + + + + true + + + + :/menuicons/qt/icons/acpi_shutdown.ico:/menuicons/qt/icons/acpi_shutdown.ico + + + Force shutdown + + + Force shutdown + + + true + + + false + + + + + false + + + + :/menuicons/qt/icons/send_cad.ico:/menuicons/qt/icons/send_cad.ico + + + &Ctrl+Alt+Del + + + Ctrl+Alt+Del + + + false + + + false + + + false + + + + + + :/menuicons/qt/icons/settings.ico:/menuicons/qt/icons/settings.ico + + + &Settings... + + + QAction::MenuRole::NoRole + + + false + + + + + + :/settings/qt/icons/86Box-yellow.ico:/settings/qt/icons/86Box-yellow.ico + + + New Machine + + + New Machine + + + + + Preferences + + + Preferences + + + QAction::MenuRole::PreferencesRole + + + + + true + + + + :/menuicons/qt/icons/run.ico:/menuicons/qt/icons/run.ico + + + Start + + + false + + + + + Check for updates + + + + + + + + diff --git a/src/qt/qt_vmmanager_model.cpp b/src/qt/qt_vmmanager_model.cpp new file mode 100644 index 000000000..848970f80 --- /dev/null +++ b/src/qt/qt_vmmanager_model.cpp @@ -0,0 +1,163 @@ +/* +* 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. +* +* 86Box VM manager model module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed + */ + +#include +#include "qt_vmmanager_model.hpp" + +VMManagerModel::VMManagerModel() { + auto machines_vec = VMManagerSystem::scanForConfigs(); + for ( const auto& each_config : machines_vec) { + machines.append(each_config); + connect(each_config, &VMManagerSystem::itemDataChanged, this, &VMManagerModel::modelDataChanged); + } +} + +VMManagerModel::~VMManagerModel() { + for ( auto machine : machines) { + delete machine; + } +} + +int +VMManagerModel::rowCount(const QModelIndex &parent) const { + return machines.size(); +} + +QVariant +VMManagerModel::data(const QModelIndex &index, int role) const { + if (!index.isValid()) + return {}; + + if (index.row() >= machines.size()) + return {}; + + switch (role) { + case Qt::DisplayRole: + return machines.at(index.row())->displayName; + case ConfigName: + return machines.at(index.row())->config_name; + case ConfigDir: + return machines.at(index.row())->config_dir; + case ConfigFile: + return machines.at(index.row())->config_file.canonicalFilePath(); + case UUID: + return machines.at(index.row())->uuid; + case Notes: + return machines.at(index.row())->notes; + case SearchList: + return machines.at(index.row())->searchTerms; + case LastUsed: + return machines.at(index.row())->timestamp(); + case Icon: + return machines.at(index.row())->icon; + case Qt::ToolTipRole: + return machines.at(index.row())->shortened_dir; + case Qt::UserRole: + return machines.at(index.row())->getAll("General"); + case ProcessStatusString: + return machines.at(index.row())->getProcessStatusString(); + case ProcessStatus: + return QVariant::fromValue(machines.at(index.row())->getProcessStatus()); + default: + return {}; + } +} + +QVariant +VMManagerModel::headerData(int section, Qt::Orientation orientation, int role) const { + + if (role != Qt::DisplayRole) + return {}; + + if (orientation == Qt::Horizontal) + return QStringLiteral("Column %1").arg(section); + else + return QStringLiteral("Row %1").arg(section); +} + +VMManagerSystem * +VMManagerModel::getConfigObjectForIndex(const QModelIndex &index) const +{ + return machines.at(index.row()); +} +void +VMManagerModel::reload(QWidget* parent) +{ + // Scan for configs + auto machines_vec = VMManagerSystem::scanForConfigs(parent); + for (const auto &scanned_config : machines_vec) { + int found = 0; + for (const auto &existing_config : machines) { + if (*scanned_config == *existing_config) { + found = 1; + } + } + if (!found) { + addConfigToModel(scanned_config); + } + } + // TODO: Remove missing configs +} + +QModelIndex +VMManagerModel::getIndexForConfigFile(const QFileInfo& config_file) +{ + int object_index = 0; + for (const auto& config_object: machines) { + if (config_object->config_file == config_file) { + return this->index(object_index); + } + object_index++; + } + return {}; +} + +void +VMManagerModel::addConfigToModel(VMManagerSystem *system_config) +{ + beginInsertRows(QModelIndex(), this->rowCount(QModelIndex()), this->rowCount(QModelIndex())); + machines.append(system_config); + connect(system_config, &VMManagerSystem::itemDataChanged, this, &VMManagerModel::modelDataChanged); + endInsertRows(); +} +void +VMManagerModel::modelDataChanged() +{ + // Inform the model + emit dataChanged(this->index(0), this->index(machines.size()-1)); + // Inform any interested observers + emit systemDataChanged(); +} + +void +VMManagerModel::updateDisplayName(const QModelIndex &index, const QString &newDisplayName) +{ + machines.at(index.row())->setDisplayName(newDisplayName); + modelDataChanged(); +} +QHash +VMManagerModel::getProcessStats() +{ + QHash stats; + for (const auto& system: machines) { + if (system->getProcessStatus() != VMManagerSystem::ProcessStatus::Stopped) { + auto statusString = system->getProcessStatusString(); + stats[statusString] += 1; + } + } + return stats; +} \ No newline at end of file diff --git a/src/qt/qt_vmmanager_model.hpp b/src/qt/qt_vmmanager_model.hpp new file mode 100644 index 000000000..bc13cc16f --- /dev/null +++ b/src/qt/qt_vmmanager_model.hpp @@ -0,0 +1,91 @@ +/* +* 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. +* +* Header for 86Box VM manager model module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed + */ + +#ifndef QT_VMMANAGER_MODEL_H +#define QT_VMMANAGER_MODEL_H + + +#include "qt_vmmanager_system.hpp" + +#include + +class VMManagerModel final : public QAbstractListModel { + + Q_OBJECT + +public: + // VMManagerModel(const QStringList &strings, QObject *parent = nullptr) + // : QAbstractListModel(parent), machines(strings) {} + VMManagerModel(); + ~VMManagerModel() override; + enum Roles { + ProcessStatusString = Qt::UserRole + 1, + ProcessStatus, + DisplayName, + ConfigName, + ConfigDir, + ConfigFile, + LastUsed, + UUID, + Notes, + SearchList, + Icon + }; + + [[nodiscard]] int rowCount(const QModelIndex &parent) const override; + [[nodiscard]] QVariant data(const QModelIndex &index, int role) const override; + [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, + int role) const override; + void addConfigToModel(VMManagerSystem *system_config); + + [[nodiscard]] VMManagerSystem * getConfigObjectForIndex(const QModelIndex &index) const; + QModelIndex getIndexForConfigFile(const QFileInfo& config_file); + void reload(QWidget* parent = nullptr); + void updateDisplayName(const QModelIndex &index, const QString &newDisplayName); + QHash getProcessStats(); +signals: + void systemDataChanged(); + +private: + QVector machines; + void modelDataChanged(); + +}; + +// Note: Custom QSortFilterProxyModel is included here instead of its own file as +// its only use is in this model + +class StringListProxyModel final : public QSortFilterProxyModel { +public: + explicit StringListProxyModel(QObject *parent = nullptr) : QSortFilterProxyModel(parent) {} + +protected: + [[nodiscard]] bool filterAcceptsRow(const int sourceRow, const QModelIndex &sourceParent) const override { + const QModelIndex index = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent); + + QStringList stringList = sourceModel()->data(index, VMManagerModel::Roles::SearchList).toStringList(); + + const QRegularExpression regex = filterRegularExpression(); + + const auto result = std::any_of(stringList.begin(), stringList.end(), [®ex](const QString &string) { + return regex.match(string).hasMatch(); + }); + return result; + } +}; + +#endif //QT_VMMANAGER_MODEL_H diff --git a/src/qt/qt_vmmanager_preferences.cpp b/src/qt/qt_vmmanager_preferences.cpp new file mode 100644 index 000000000..0730f875b --- /dev/null +++ b/src/qt/qt_vmmanager_preferences.cpp @@ -0,0 +1,82 @@ +/* +* 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. +* +* 86Box VM manager preferences module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include +#include + +#include "qt_vmmanager_preferences.hpp" +#include "qt_vmmanager_config.hpp" +#include "ui_qt_vmmanager_preferences.h" + +extern "C" { +#include <86box/86box.h> +} + +VMManagerPreferences:: +VMManagerPreferences(QWidget *parent) : ui(new Ui::VMManagerPreferences) +{ + ui->setupUi(this); + ui->dirSelectButton->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirIcon)); + connect(ui->dirSelectButton, &QPushButton::clicked, this, &VMManagerPreferences::chooseDirectoryLocation); + + const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + const auto configSystemDir = config->getStringValue("system_directory"); + if(!configSystemDir.isEmpty()) { + // Prefer this one + ui->systemDirectory->setText(configSystemDir); + } else if(!QString(vmm_path).isEmpty()) { + // If specified on command line + ui->systemDirectory->setText(QDir(vmm_path).path()); + } + + // TODO: Defaults + const auto configUpdateCheck = config->getStringValue("update_check").toInt(); + ui->updateCheckBox->setChecked(configUpdateCheck); + const auto useRegexSearch = config->getStringValue("regex_search").toInt(); + ui->regexSearchCheckBox->setChecked(useRegexSearch); + + +} + +VMManagerPreferences::~ +VMManagerPreferences() + = default; + +// Bad copy pasta from machine add +void +VMManagerPreferences::chooseDirectoryLocation() +{ + // TODO: FIXME: This is pulling in the CLI directory! Needs to be set properly elsewhere + const auto directory = QFileDialog::getExistingDirectory(this, "Choose directory", QDir(vmm_path).path()); + ui->systemDirectory->setText(QDir::toNativeSeparators(directory)); +} + +void +VMManagerPreferences::accept() +{ + const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + config->setStringValue("system_directory", ui->systemDirectory->text()); + config->setStringValue("update_check", ui->updateCheckBox->isChecked() ? "1" : "0"); + config->setStringValue("regex_search", ui->regexSearchCheckBox->isChecked() ? "1" : "0"); + QDialog::accept(); +} + +void +VMManagerPreferences::reject() +{ + QDialog::reject(); +} \ No newline at end of file diff --git a/src/qt/qt_vmmanager_preferences.hpp b/src/qt/qt_vmmanager_preferences.hpp new file mode 100644 index 000000000..aedba862a --- /dev/null +++ b/src/qt/qt_vmmanager_preferences.hpp @@ -0,0 +1,46 @@ +/* +* 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. +* +* Header for 86Box VM manager preferences module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef VMMANAGER_PREFERENCES_H +#define VMMANAGER_PREFERENCES_H + +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class VMManagerPreferences; } +QT_END_NAMESPACE + + +class VMManagerPreferences final : public QDialog +{ + Q_OBJECT +public: + explicit VMManagerPreferences(QWidget *parent = nullptr); + ~VMManagerPreferences() override; + +private: + Ui::VMManagerPreferences *ui; + QString settingsFile; +private slots: + void chooseDirectoryLocation(); +protected: + void accept() override; + void reject() override; + +}; + +#endif // VMMANAGER_PREFERENCES_H diff --git a/src/qt/qt_vmmanager_preferences.ui b/src/qt/qt_vmmanager_preferences.ui new file mode 100644 index 000000000..1743a0bfb --- /dev/null +++ b/src/qt/qt_vmmanager_preferences.ui @@ -0,0 +1,130 @@ + + + VMManagerPreferences + + + + 0 + 0 + 400 + 300 + + + + Preferences + + + + + + System Directory: + + + + + + + + 0 + + + 0 + + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + Check for updates on startup + + + + + + + Use regular expressions in search box + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + VMManagerPreferences + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + VMManagerPreferences + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/qt_vmmanager_protocol.cpp b/src/qt/qt_vmmanager_protocol.cpp new file mode 100644 index 000000000..26f8a1f93 --- /dev/null +++ b/src/qt/qt_vmmanager_protocol.cpp @@ -0,0 +1,131 @@ +/* +* 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. +* +* 86Box VM manager protocol module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed + */ + +#include "qt_vmmanager_protocol.hpp" +#include +#include +VMManagerProtocol::VMManagerProtocol(VMManagerProtocol::Sender sender) +{ + message_class = sender; +} + +VMManagerProtocol::~VMManagerProtocol() += default; + +QJsonObject +VMManagerProtocol::protocolManagerMessage(VMManagerProtocol::ManagerMessage message_type) +{ + auto json_message = constructDefaultObject(VMManagerProtocol::Sender::Manager); + json_message["message"] = managerMessageTypeToString(message_type); + return json_message; +} + +QJsonObject +VMManagerProtocol::protocolClientMessage(VMManagerProtocol::ClientMessage message_type) +{ + auto json_message = constructDefaultObject(VMManagerProtocol::Sender::Client); + json_message["message"] = clientMessageTypeToString(message_type); + return json_message; +} + +QString +VMManagerProtocol::managerMessageTypeToString(VMManagerProtocol::ManagerMessage message) +{ + QMetaEnum qme = QMetaEnum::fromType(); + return qme.valueToKey(static_cast(message)); +} + +QString +VMManagerProtocol::clientMessageTypeToString(VMManagerProtocol::ClientMessage message) +{ + QMetaEnum qme = QMetaEnum::fromType(); + return qme.valueToKey(static_cast(message)); +} + +QJsonObject +VMManagerProtocol::constructDefaultObject(VMManagerProtocol::Sender type) +{ + QJsonObject json_message; + QString sender_type = ( type == VMManagerProtocol::Sender::Client ) ? "Client" : "VMManager"; + json_message["type"] = QString(sender_type); + json_message["version"] = QStringLiteral(EMU_VERSION); + return json_message; +} +bool +VMManagerProtocol::hasRequiredFields(const QJsonObject& json_document) +{ + for (const auto& field : ProtocolRequiredFields) { + if (!json_document.contains(field)) { + qDebug("Received json missing field \"%s\"", qPrintable(field)); + return false; + } + } + return true; +} +VMManagerProtocol::ClientMessage +VMManagerProtocol::getClientMessageType(const QJsonObject &json_document) +{ + // FIXME: This key ("message") is hardcoded here. Make a hash which maps these + // required values. + QString message_type = json_document.value("message").toString(); + // Can't use switch with strings, manual compare + if (message_type == "Status") { + return VMManagerProtocol::ClientMessage::Status; + } else if (message_type == "WindowBlocked") { + return VMManagerProtocol::ClientMessage::WindowBlocked; + } else if (message_type == "WindowUnblocked") { + return VMManagerProtocol::ClientMessage::WindowUnblocked; + } else if (message_type == "RunningStateChanged") { + return VMManagerProtocol::ClientMessage::RunningStateChanged; + } + return VMManagerProtocol::ClientMessage::UnknownMessage; +} +VMManagerProtocol::ManagerMessage +VMManagerProtocol::getManagerMessageType(const QJsonObject &json_document) +{ + // FIXME: This key ("message") is hardcoded here. Make a hash which maps these + // required values. + QString message_type = json_document.value("message").toString(); + // Can't use switch with strings, manual compare + if (message_type == "RequestStatus") { + return VMManagerProtocol::ManagerMessage::RequestStatus; + } else if (message_type == "Pause") { + return VMManagerProtocol::ManagerMessage::Pause; + } if (message_type == "CtrlAltDel") { + return VMManagerProtocol::ManagerMessage::CtrlAltDel; + } if (message_type == "ShowSettings") { + return VMManagerProtocol::ManagerMessage::ShowSettings; + } if (message_type == "ResetVM") { + return VMManagerProtocol::ManagerMessage::ResetVM; + } if (message_type == "RequestShutdown") { + return VMManagerProtocol::ManagerMessage::RequestShutdown; + } if (message_type == "ForceShutdown") { + return VMManagerProtocol::ManagerMessage::ForceShutdown; + } + return VMManagerProtocol::ManagerMessage::UnknownMessage; +} +QJsonObject +VMManagerProtocol::getParams(const QJsonObject &json_document) +{ + // FIXME: This key ("params") is hardcoded here. Make a hash which maps these + // required values. + auto params_object = json_document.value("params"); + if (params_object.type() != QJsonValue::Object) { + return {}; + } + return params_object.toObject(); +} diff --git a/src/qt/qt_vmmanager_protocol.hpp b/src/qt/qt_vmmanager_protocol.hpp new file mode 100644 index 000000000..48f0a2d8f --- /dev/null +++ b/src/qt/qt_vmmanager_protocol.hpp @@ -0,0 +1,93 @@ +/* +* 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. +* +* Header for 86Box VM manager protocol module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed + */ + +#ifndef QT_VMMANAGER_PROTOCOL_H +#define QT_VMMANAGER_PROTOCOL_H + +#include +extern "C" { +#include <86box/version.h> +} + +static QVector ProtocolRequiredFields = { "type", "message" }; + +class VMManagerProtocol : QObject { + Q_OBJECT + +public: + enum class Sender { + Manager, + Client, + }; + Q_ENUM(Sender); + + enum class ManagerMessage { + RequestStatus, + Pause, + CtrlAltDel, + ShowSettings, + ResetVM, + RequestShutdown, + ForceShutdown, + UnknownMessage, + }; + + // This macro allows us to do a reverse lookup of the enum with `QMetaEnum` + Q_ENUM(ManagerMessage); + + enum class ClientMessage { + Status, + WindowBlocked, + WindowUnblocked, + RunningStateChanged, + UnknownMessage, + }; + Q_ENUM(ClientMessage); + + enum class WindowStatus { + WindowUnblocked = 0, + WindowBlocked, + }; + + enum class RunningState { + Running = 0, + Paused, + RunningWaiting, + PausedWaiting, + Unknown, + }; + Q_ENUM(RunningState); + + explicit VMManagerProtocol(Sender sender); + ~VMManagerProtocol(); + + QJsonObject protocolManagerMessage(ManagerMessage message_type); + QJsonObject protocolClientMessage(ClientMessage message_type); + static QString managerMessageTypeToString(ManagerMessage message); + static QString clientMessageTypeToString(ClientMessage message); + + static bool hasRequiredFields(const QJsonObject &json_document); + static QJsonObject getParams(const QJsonObject &json_document); + static ClientMessage getClientMessageType(const QJsonObject &json_document); + static ManagerMessage getManagerMessageType(const QJsonObject &json_document); + +private: + Sender message_class; + static QJsonObject constructDefaultObject(VMManagerProtocol::Sender type); +}; + +#endif // QT_VMMANAGER_PROTOCOL_H diff --git a/src/qt/qt_vmmanager_serversocket.cpp b/src/qt/qt_vmmanager_serversocket.cpp new file mode 100644 index 000000000..50ff352d6 --- /dev/null +++ b/src/qt/qt_vmmanager_serversocket.cpp @@ -0,0 +1,207 @@ +/* +* 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. +* +* 86Box VM manager server socket module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed + */ + +#include "qt_vmmanager_serversocket.hpp" +#include +#include +#include +#include +#include +#include + +VMManagerServerSocket::VMManagerServerSocket(const QFileInfo &config_path, const ServerType type) +{ + server_type = type; + config_file = config_path; + serverIsRunning = false; + socket = nullptr; + server = new QLocalServer; + setupVars(); +} + +VMManagerServerSocket::~VMManagerServerSocket() +{ + delete server; +} + +bool +VMManagerServerSocket::startServer() { + + // Remove socket file (if it exists) in order to start a new one + qInfo("Socket path is %s", qPrintable(socket_path.filePath())); + if (socket_path.exists() and !socket_path.isDir()) { + auto socket_file = new QFile(socket_path.filePath()); + if (!socket_file->remove()) { + qInfo("Failed to remove the old socket file (Error %i): %s", socket_file->error(), qPrintable(socket_file->errorString())); + return false; + } + } + + if (server->listen(socket_path.fileName())) { + serverIsRunning = true; + connect(server, &QLocalServer::newConnection, this, &VMManagerServerSocket::serverConnectionReceived); + return true; + } else { + qInfo("Failed to start server: %s", qPrintable(server->errorString())); + serverIsRunning = false; + return false; + } +} + +void +VMManagerServerSocket::serverConnectionReceived() { + qDebug("Connection received on %s", qPrintable(socket_path.fileName())); + socket = server->nextPendingConnection(); + if(!socket) { + qInfo("Invalid socket when trying to receive the connection"); + return; + } + connect(socket, &QLocalSocket::readyRead, this, &VMManagerServerSocket::serverReceivedMessage); + connect(socket, &QLocalSocket::disconnected, this, &VMManagerServerSocket::serverDisconnected); +} + +void +VMManagerServerSocket::serverReceivedMessage() { + + // Handle legacy socket connections first. These connections only receive + // information on window status + if(server_type == VMManagerServerSocket::ServerType::Legacy) { + QByteArray tempString = socket->read(1); + int window_obscured = tempString.toInt(); + emit windowStatusChanged(window_obscured); + return; + } + + // Normal connections here + QDataStream stream(socket); + stream.setVersion(QDataStream::Qt_5_7); + QByteArray jsonData; + for (;;) { + // Start a transaction + stream.startTransaction(); + // Try to read the data + stream >> jsonData; + if (stream.commitTransaction()) { + QJsonParseError parse_error{}; + // Validate the received data to make sure it's valid json + const QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parse_error); + if (parse_error.error == QJsonParseError::NoError) { + // The data received was valid json + if (jsonDoc.isObject()) { + // The data is a valid json object + emit dataReceived(); + jsonReceived(jsonDoc.object()); + } + } + // The data was not valid json. + // Loop and try to read more data + } else { + // read failed, socket is reverted to its previous state (before the transaction) + // exit the loop and wait for more data to become available + break; + } + } +} + +void +VMManagerServerSocket::serverSendMessage(VMManagerProtocol::ManagerMessage protocol_message, const QStringList& arguments) const { + if(!socket) { + qInfo("Cannot send message: Invalid socket"); + return; + } + + // Regular connection + QDataStream stream(socket); + stream.setVersion(QDataStream::Qt_5_7); + auto packet = new VMManagerProtocol(VMManagerProtocol::Sender::Manager); + auto jsonMessage = packet->protocolManagerMessage(protocol_message); + stream << QJsonDocument(jsonMessage).toJson(QJsonDocument::Compact); +} + +void +VMManagerServerSocket::serverDisconnected() +{ + qInfo("Connection disconnected"); +} +void +VMManagerServerSocket::jsonReceived(const QJsonObject &json) +{ + // The serialization portion has already validated the message as json. + // Now ensure it has the required fields. + if (!VMManagerProtocol::hasRequiredFields(json)) { + // TODO: Error handling of some sort, emit signals + qDebug("Invalid message received from client: required fields missing. Object:"); + qDebug() << json; + return; + } +// qDebug().noquote() << Q_FUNC_INFO << json; + QJsonObject params_object; + + auto message_type = VMManagerProtocol::getClientMessageType(json); + switch (message_type) { + case VMManagerProtocol::ClientMessage::Status: + qDebug("Status message received from client"); + break; + case VMManagerProtocol::ClientMessage::WindowBlocked: + qDebug("Window blocked message received from client"); + emit windowStatusChanged(static_cast(VMManagerProtocol::WindowStatus::WindowBlocked)); + break; + case VMManagerProtocol::ClientMessage::WindowUnblocked: + qDebug("Window unblocked received from client"); + emit windowStatusChanged(static_cast(VMManagerProtocol::WindowStatus::WindowUnblocked)); + break; + case VMManagerProtocol::ClientMessage::RunningStateChanged: + qDebug("Running state change received from client"); + params_object = VMManagerProtocol::getParams(json); + if (!params_object.isEmpty()) { + // valid object + if(params_object.value("status").type() == QJsonValue::Double) { + // has status key, value is an int (qt assigns it as Double) + emit runningStatusChanged(static_cast(params_object.value("status").toInt())); + } + } + break; + default: + qDebug("Unknown client message type received:"); + qDebug() << json; + return; + } +} + +void +VMManagerServerSocket::setupVars() +{ + QString unique_name = QCryptographicHash::hash(config_file.path().toUtf8().constData(), QCryptographicHash::Algorithm::Sha256).toHex().right(6); + socket_path.setFile(QStandardPaths::writableLocation(QStandardPaths::TempLocation) + "/" + QApplication::applicationName() + ".socket." + unique_name); +} + +QString +VMManagerServerSocket::getSocketPath() const +{ + if (server) { + return server->fullServerName(); + } + return {}; +} + +QString +VMManagerServerSocket::serverTypeToString(VMManagerServerSocket::ServerType server_type_lookup) +{ + QMetaEnum qme = QMetaEnum::fromType(); + return qme.valueToKey(static_cast(server_type_lookup)); + +} diff --git a/src/qt/qt_vmmanager_serversocket.hpp b/src/qt/qt_vmmanager_serversocket.hpp new file mode 100644 index 000000000..3e6e43a80 --- /dev/null +++ b/src/qt/qt_vmmanager_serversocket.hpp @@ -0,0 +1,82 @@ +/* +* 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. +* +* Header for 86Box VM manager server socket module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed + */ + +#ifndef QT_VMMANAGER_SERVERSOCKET_H +#define QT_VMMANAGER_SERVERSOCKET_H + +#include +#include +#include +#include +#include +#include "qt_vmmanager_protocol.hpp" + +// This macro helps give us the required `qHash()` function in order to use the +// enum as a hash key +#define QHASH_FOR_CLASS_ENUM(T) \ +inline uint qHash(const T &t, uint seed) { \ + return ::qHash(static_cast::type>(t), seed); \ +} + +class VMManagerServerSocket : public QWidget { + + Q_OBJECT + +public: + + enum class ServerType { + Standard, + Legacy, + }; + // This macro allows us to do a reverse lookup of the enum with `QMetaEnum` + Q_ENUM(ServerType) + + QHASH_FOR_CLASS_ENUM(ServerType) + + explicit VMManagerServerSocket(const QFileInfo &config_path, ServerType type = ServerType::Standard); + ~VMManagerServerSocket() override; + + QFileInfo socket_path; + QFileInfo config_file; + + QLocalServer *server; + QLocalSocket *socket; + ServerType server_type; + bool serverIsRunning; + + // Server functions + bool startServer(); + void serverConnectionReceived(); + void serverReceivedMessage(); + void serverSendMessage(VMManagerProtocol::ManagerMessage protocol_message, const QStringList& arguments = QStringList()) const; + static void serverDisconnected(); + void jsonReceived(const QJsonObject &json); + QString getSocketPath() const; + + static QString serverTypeToString(ServerType server_type_lookup); + + void setupVars(); + +signals: + void dataReceived(); + void windowStatusChanged(int status); + void runningStatusChanged(VMManagerProtocol::RunningState state); + + +}; + +#endif // QT_VMMANAGER_SERVERSOCKET_H diff --git a/src/qt/qt_vmmanager_system.cpp b/src/qt/qt_vmmanager_system.cpp new file mode 100644 index 000000000..08853feab --- /dev/null +++ b/src/qt/qt_vmmanager_system.cpp @@ -0,0 +1,922 @@ +/* +* 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. +* +* 86Box VM manager system module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qt_vmmanager_system.hpp" +// #include "qt_vmmanager_details_section.hpp" +#include "qt_vmmanager_detailsection.hpp" + + +extern "C" { +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/video.h> +// #include <86box/vid_xga_device.h> +#include <86box/machine.h> +#include <86box/plat.h> +#include <86box/sound.h> +#include +#include <86box/thread.h> // required for network.h +#include <86box/timer.h> // required for network.h and fdd.h +#include <86box/cdrom.h> +#include <86box/scsi.h> +#include <86box/fdd.h> +#include <86box/gameport.h> +#include <86box/midi.h> +#include <86box/network.h> +#include <86box/mouse.h> +} + +VMManagerSystem::VMManagerSystem(const QString &sysconfig_file) { + + // The 86Box configuration file + config_file = QFileInfo(sysconfig_file); + // The default name of the system. This is the name of the directory + // that contains the 86box configuration file + config_name = config_file.dir().dirName(); + // The full path of the directory that contains the 86box configuration file + config_dir = shortened_dir = config_file.dir().path(); + process_status = ProcessStatus::Stopped; + // Main 86Box uses usr_path for UUID which includes the trailing slash. + // Make sure to append the slash here so the UUIDs will match + auto uuid_path = config_dir; + if (!uuid_path.endsWith("/")) { + uuid_path.append("/"); + } + // In the configuration file the UUID is used as a unique value + uuid = QUuid::createUuidV5(QUuid{}, uuid_path).toString(QUuid::WithoutBraces); + // That unique value is used to map the information to each individual system. + config_settings = new VMManagerConfig(VMManagerConfig::ConfigType::System, uuid); + + // On non-windows platforms, shortened_dir will replace the home directory path with ~ + // and be used as the tool tip in the list view +#if not defined(Q_OS_WINDOWS) + if (config_dir.startsWith(QDir::homePath())) { + shortened_dir.replace(QDir::homePath(), "~"); + } +#endif + loadSettings(); + setupPaths(); + // Paths must be setup before vars! + setupVars(); + + serverIsRunning = false; + window_obscured = false; + + find86BoxBinary(); + platform = QApplication::platformName(); + process = new QProcess(); + connect(process, &QProcess::stateChanged, this, &VMManagerSystem::processStatusChanged); + + // Server type for this instance (Standard should always be used instead of Legacy) + socket_server_type = VMManagerServerSocket::ServerType::Standard; + socket_server = new VMManagerServerSocket(config_file, socket_server_type); + + // NOTE: When unique names or UUIDs are written to the individual VM config file, use that + // here instead of the auto-generated unique_name + // Save settings once everything is initialized + saveSettings(); +} + +VMManagerSystem::~VMManagerSystem() { + delete socket_server; +} + +QVector +VMManagerSystem::scanForConfigs(QWidget* parent, const QString &searchPath) +{ + QProgressDialog progDialog(parent); + unsigned int found = 0; + progDialog.setCancelButton(nullptr); + progDialog.setWindowTitle(tr("Searching for VMs...")); + progDialog.setMinimumDuration(0); + progDialog.setValue(0); + progDialog.setMinimum(0); + progDialog.setMaximum(0); + progDialog.setWindowFlags(progDialog.windowFlags() & ~Qt::WindowCloseButtonHint); + QElapsedTimer scanTimer; + scanTimer.start(); + QVector system_configs; + + const auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + auto systemDirConfig = config->getStringValue("system_directory"); + + const auto config_file_name = QString("86box.cfg"); + const QStringList filters = {config_file_name}; + QStringList matches; + // TODO: Preferences. Once I get the CLI args worked out. + // For now it just takes vmm_path from the CLI + QString search_directory; + // if(searchPath.isEmpty()) { + // // If the location isn't specified in function call, use the one loaded + // // from the config file + // search_directory = systemDirConfig; + // } else { + // search_directory = searchPath; + // } + + search_directory = searchPath.isEmpty()? vmm_path : searchPath; + + if(!QDir(search_directory).exists()) { + //qWarning() << "Path" << search_directory << "does not exist. Cannot continue"; + QDir(search_directory).mkpath("."); + //return {}; + } + + QDirIterator dir_iterator(search_directory, filters, QDir::Files, QDirIterator::Subdirectories); + + qInfo("Searching %s for %s", qPrintable(search_directory), qPrintable(config_file_name)); + + QElapsedTimer timer; + timer.start(); + while (dir_iterator.hasNext()) { + found++; + progDialog.setLabelText(tr("Found %1").arg(QString::number(found))); + QApplication::processEvents(); + QString filename = dir_iterator.next(); + matches.append(filename); + } + + const auto scanElapsed = timer.elapsed(); + qDebug().noquote().nospace() << "Found " << matches.size() << " configs in " << search_directory <<". Scan took " << scanElapsed << " ms"; + + timer.restart(); + // foreach (QFileInfo hit, matches) { + // system_configs.append(new VMManagerSystem(hit)); + // } + progDialog.setMaximum(found); + progDialog.setValue(0); + unsigned int appended = 0; + for (const auto &filename : matches) { + system_configs.append(new VMManagerSystem(filename)); + appended++; + progDialog.setLabelText(system_configs.last()->displayName); + progDialog.setValue(appended); + QApplication::processEvents(); + } + if (matches.size()) { + auto elapsed = timer.elapsed(); + qDebug() << "Load loop took" << elapsed << "ms for" << matches.size() << "loads"; + qDebug() << "Overall scan time was" << scanTimer.elapsed() << "ms, average" << elapsed / matches.size() << "ms / load"; + } + return system_configs; +} + +QString +VMManagerSystem::generateTemporaryFilename() +{ + QTemporaryFile tempFile; + // File will be closed once the QTemporaryFile object goes out of scope + tempFile.setAutoRemove(true); + tempFile.open(); + return tempFile.fileName(); +} + +QFileInfoList +VMManagerSystem::getScreenshots() { + + // Don't bother unless the directory exists + if(!screenshot_directory.exists()) { + return {}; + } + + auto screen_scan_dir = QDir(screenshot_directory.path(), "Monitor_1*", QDir::SortFlag::LocaleAware | QDir::SortFlag::IgnoreCase, QDir::Files); + auto screenshot_files = screen_scan_dir.entryInfoList(); + return screenshot_files; +} + +void +VMManagerSystem::loadSettings() +{ + // First, load the information from the 86box.cfg + QSettings settings(config_file.filePath(), QSettings::IniFormat); + if (settings.status() != QSettings::NoError) { + qWarning() << "Error loading" << config_file.path() << " status:" << settings.status(); + } + // qInfo() << "Loaded "<< config_file.filePath() << "status:" << settings.status(); + + // Clear out the config hash in case the config is reloaded + for (const auto &outer_key : config_hash.keys()) { + config_hash[outer_key].clear(); + } + + // General + for (const auto &key_name : settings.childKeys()) { + config_hash["General"][key_name] = settings.value(key_name).toString(); + } + + for (auto &group_name : settings.childGroups()) { + settings.beginGroup(group_name); + for (const auto &key_name : settings.allKeys()) { + QString setting_value; + // QSettings will interpret lines with commas as QStringList. + // Check for it and join them back to a string. + if (settings.value(key_name).type() == QVariant::StringList) { + setting_value = settings.value(key_name).toStringList().join(", "); + } else { + setting_value = settings.value(key_name).toString(); + } + config_hash[group_name][key_name] = setting_value; + } + settings.endGroup(); + } + + // Next, load the information from the vmm config for this system + // Display name + auto loadedDisplayName = config_settings->getStringValue("display_name"); + if (!loadedDisplayName.isEmpty()) { + displayName = loadedDisplayName; + } else { + displayName = config_name; + } + // Notes + auto loadedNotes = config_settings->getStringValue("notes"); + if (!loadedNotes.isEmpty()) { + notes = loadedNotes; + } + // Timestamp + auto loadedTimestamp = config_settings->getStringValue("timestamp"); + if (!loadedTimestamp.isEmpty()) { + // Make sure it is valid + if (auto newTimestamp = QDateTime::fromString(loadedTimestamp, Qt::ISODate); newTimestamp.isValid()) { + lastUsedTimestamp = newTimestamp; + } + } + // Icon + auto loadedIcon = config_settings->getStringValue("icon"); + if (!loadedIcon.isEmpty()) { + icon = loadedIcon; + } +} +void +VMManagerSystem::saveSettings() +{ + if(!isValid()) { + return; + } + config_settings->setStringValue("system_name", config_name); + config_settings->setStringValue("config_file", config_file.canonicalFilePath()); + config_settings->setStringValue("config_dir", config_file.canonicalPath()); + if (displayName != config_name) { + config_settings->setStringValue("display_name", displayName); + } else { + config_settings->remove("display_name"); + } + + config_settings->setStringValue("notes", notes); + if(lastUsedTimestamp.isValid()) { + config_settings->setStringValue("timestamp", lastUsedTimestamp.toString(Qt::ISODate)); + } + config_settings->setStringValue("icon", icon); + generateSearchTerms(); +} +void +VMManagerSystem::generateSearchTerms() +{ + searchTerms.clear(); + for (const auto &config_key : config_hash.keys()) { + // searchTerms.append(config_hash[config_key].values()); + // brute force temporarily don't add paths + for(const auto &value: config_hash[config_key].values()) { + if(!value.startsWith("/")) { + searchTerms.append(value); + } + } + } + searchTerms.append(display_table.values()); + searchTerms.append(displayName); + searchTerms.append(config_name); + QRegularExpression whitespaceRegex("\\s+"); + searchTerms.append(notes.split(whitespaceRegex)); +} +void +VMManagerSystem::updateTimestamp() +{ + lastUsedTimestamp = QDateTime::currentDateTimeUtc(); + saveSettings(); +} + +QString +VMManagerSystem::getAll(const QString& category) const { + auto value = config_hash[category].keys().join(", "); + return value; +} + +QHash> +VMManagerSystem::getConfigHash() const +{ + return config_hash; +} + +void +VMManagerSystem::setDisplayName(const QString &newDisplayName) +{ + // If blank, reset to the default + if (newDisplayName.isEmpty()) { + displayName = config_name; + } else { + displayName = newDisplayName; + } + saveSettings(); +} +void +VMManagerSystem::setNotes(const QString &newNotes) +{ + notes = newNotes; + saveSettings(); +} +bool +VMManagerSystem::isValid() const +{ + return config_file.exists() && config_file.isFile() && config_file.size() != 0; +} + +bool +VMManagerSystem::isProcessRunning() const +{ + return process->processId() != 0; +} + +qint64 +VMManagerSystem::processId() const +{ + return process->processId(); +} + +QHash +VMManagerSystem::getCategory(const QString &category) const { + return config_hash[category]; +} + +void +VMManagerSystem::find86BoxBinary() { + // We'll use our own self to launch the VMs + main_binary = QFileInfo(QCoreApplication::applicationFilePath()); +} + +bool +VMManagerSystem::has86BoxBinary() { + return main_binary.exists(); +} + +void +VMManagerSystem::launchMainProcess() { + + if(!has86BoxBinary()) { + qWarning("No binary found! returning"); + return; + } + + // start the server first to get the socket name + if (!serverIsRunning) { + if(!startServer()) { + // FIXME: Better error handling + qInfo("Failed to start VM Manager server"); + return; + } + } + setProcessEnvVars(); + QString program = main_binary.filePath(); + QStringList args; + args << "-P" << config_dir; + args << "--vmname" << displayName; + process->setProgram(program); + process->setArguments(args); + qDebug() << Q_FUNC_INFO << " Full Command:" << process->program() << " " << process->arguments(); + process->start(); + updateTimestamp(); +} + +void +VMManagerSystem::startButtonPressed() { + launchMainProcess(); +} + +void +VMManagerSystem::launchSettings() { + if(!has86BoxBinary()) { + qWarning("No binary found! returning"); + return; + } + + // If the system is already running, instruct it to show settings + if (process->processId() != 0) { + socket_server->serverSendMessage(VMManagerProtocol::ManagerMessage::ShowSettings); + return; + } + + // Otherwise, launch the system with the settings parameter + setProcessEnvVars(); + QString program = main_binary.filePath(); + QStringList open_command_args; + QStringList args; + args << "-P" << config_dir << "-S"; + process->setProgram(program); + process->setArguments(args); + qDebug() << Q_FUNC_INFO << " Full Command:" << process->program() << " " << process->arguments(); + process->start(); +} + +void +VMManagerSystem::setupPaths() { + // application_temp_directory.setPath(QStandardPaths::writableLocation(QStandardPaths::TempLocation)); + // standard_temp_directory.setPath(QStandardPaths::writableLocation(QStandardPaths::TempLocation)); + // QString temp_subdir = QApplication::applicationName(); + // if (!application_temp_directory.exists(temp_subdir)) { + // // FIXME: error checking + // application_temp_directory.mkdir(temp_subdir); + // } + // // QT always replaces `/` with native separators, so it is safe to use here for all platforms + // application_temp_directory.setPath(application_temp_directory.path() + "/" + temp_subdir); + // app_data_directory.setPath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)); + // // TODO: come back here and update with the new plat_get_global_* + // if (!app_data_directory.exists()) { + // // FIXME: Error checking + // app_data_directory.mkpath(app_data_directory.path()); + // } + screenshot_directory.setPath(config_dir + "/" + "screenshots"); +} + +void +VMManagerSystem::setupVars() { + unique_name = QCryptographicHash::hash(config_file.path().toUtf8().constData(), QCryptographicHash::Algorithm::Sha256).toHex().right(9); + // unique_name = "aaaaaa"; + // Set up the display vars + // This will likely get moved out to its own class + // This will likely get moved out to its own class + auto machine_config = getCategory("Machine"); + auto video_config = getCategory("Video"); + auto disk_config = getCategory("Hard disks"); + auto audio_config = getCategory("Sound"); + auto network_config = getCategory("Network"); + auto input_config = getCategory("Input devices"); + auto floppy_cdrom_config = getCategory("Floppy and CD-ROM drives"); + auto scsi_config = getCategory("Storage controllers"); + auto ports_config = getCategory("Ports (COM & LPT)"); + // auto general_config = getCategory("General"); + // auto config_uuid = QString("Not set"); + // if(!general_config["uuid"].isEmpty()) { + // config_uuid = general_config["uuid"]; + // qDebug() << "btw config dir:" << config_dir; + // } + // qDebug() << "Generated UUID:" << uuid; + // qDebug() << "Config file UUID:" << config_uuid; + auto machine_name = QString(); + int i = 0; + int ram_granularity = 0; + // Machine + for (int ci = 0; ci < machine_count(); ++ci) { + if (machine_available(ci)) { + if (machines[ci].internal_name == machine_config["machine"]) { + machine_name = machines[ci].name; + ram_granularity = machines[ci].ram.step; + } + } + } + display_table[Display::Name::Machine] = machine_name; + + // CPU: Combine name with speed + auto cpu_name = QString(); + while (cpu_families[i].package != 0) { + if (cpu_families[i].internal_name == machine_config["cpu_family"]) { + cpu_name = QString("%1 %2").arg(cpu_families[i].manufacturer, cpu_families[i].name); + } + i++; + } + int speed_display = machine_config["cpu_speed"].toInt() / 1000000; + cpu_name.append(QString::number(speed_display).prepend(" / ")); + cpu_name.append(QCoreApplication::translate("", "MHz").prepend(' ')); + display_table[Display::Name::CPU] = cpu_name; + + // Memory + int divisor = (ram_granularity < 1024) ? 1 : 1024; + QString display_unit = (divisor == 1) ? "KB" : "MB"; + auto mem_display = QString::number(machine_config["mem_size"].toInt() / divisor); + mem_display.append(QCoreApplication::translate("", display_unit.toUtf8().constData()).prepend(' ')); + display_table[Display::Name::Memory] = mem_display; + + // Video card + int video_int = video_get_video_from_internal_name(video_config["gfxcard"].toUtf8().data()); + const device_t* video_dev = video_card_getdevice(video_int); + display_table[Display::Name::Video] = DeviceConfig::DeviceName(video_dev, video_get_internal_name(video_int), 1); + if (!video_config["voodoo"].isEmpty()) { + // FIXME: Come back to this later to add more for secondary video +// display_table[Display::Name::Video].append(" (with voodoo)"); + display_table[Display::Name::Voodoo] = "Voodoo enabled"; + } + + // Drives + // First the number of disks + QMap disks; + for(const auto& key: disk_config.keys()) { + // Assuming the format hdd_NN_* + QStringList pieces = key.split('_'); + QString disk = QString("%1_%2").arg(pieces.at(0), pieces.at(1)); + if(!disk.isEmpty()) { + disks[disk] = 1; + } + } + // Next, the types + QHash bus_types; + for (const auto& key: disks.keys()) { + auto disk_parameter_key = QString("%1_parameters").arg(key); + QStringList pieces = disk_config[disk_parameter_key].split(","); + QString bus_type = pieces.value(pieces.length() - 1).trimmed(); + bus_types[bus_type] = 1; + } + QString disks_display = tr("%n disk(s)", "", disks.count()); + if (disks.count()) { + disks_display.append(" / ").append(bus_types.keys().join(", ").toUpper()); + } +// display_table[Display::Name::Disks] = disks_display; + + // Drives + QString new_disk_display; + for (const auto& key: disks.keys()) { + auto disk_parameter_key = QString("%1_parameters").arg(key); + // Converting a string to an int back to a string to remove the zero (e.g. 01 to 1) + auto disk_number = QString::number(key.split("_").last().toInt()); + QStringList pieces = disk_config[disk_parameter_key].split(","); + QString sectors = pieces.value(0).trimmed(); + QString heads = pieces.value(1).trimmed(); + QString cylinders = pieces.value(2).trimmed(); + QString bus_type = pieces.value(pieces.length() - 1).trimmed(); + // Add separator for each subsequent value, skipping the first + if(!new_disk_display.isEmpty()) { + new_disk_display.append(QString("%1").arg(VMManagerDetailSection::sectionSeparator)); + } + int diskSizeRaw = (cylinders.toInt() * heads.toInt() * sectors.toInt()) >> 11; + QString diskSizeFinal; + QString unit = "MiB"; + if(diskSizeRaw > 1000) { + unit = "GiB"; + diskSizeFinal = QString::number(diskSizeRaw * 1.0 / 1000, 'f', 1); + } else { + diskSizeFinal = QString::number(diskSizeRaw); + } + // Only prefix each disk when there are multiple disks + QString diskNumberDisplay = disks.count() > 1 ? QString("Disk %1: ").arg(disk_number) : ""; + new_disk_display.append(QString("%1%2 %3 (%4)").arg(diskNumberDisplay, diskSizeFinal, unit, bus_type.toUpper())); + } + if(new_disk_display.isEmpty()) { + new_disk_display = "No disks"; + } + display_table[Display::Name::Disks] = new_disk_display; + + // Floppy & CD-ROM + QStringList floppyDevices; + QStringList cdromDevices; + static auto floppy_match = QRegularExpression("fdd_\\d\\d_type", QRegularExpression::CaseInsensitiveOption); + static auto cdrom_match = QRegularExpression("cdrom_\\d\\d_type", QRegularExpression::CaseInsensitiveOption); + for(const auto& key: floppy_cdrom_config.keys()) { + if(key.contains(floppy_match)) { + // auto device_number = key.split("_").at(1); + auto floppy_internal_name = QString(floppy_cdrom_config[key]); + // Not interested in the nones + if(floppy_internal_name == "none") { + continue; + } + auto floppy_type = fdd_get_from_internal_name(floppy_internal_name.toUtf8().data()); + if(auto fddName = QString(fdd_getname(floppy_type)); !fddName.isEmpty()) { + floppyDevices.append(fddName); + } + } + if(key.contains(cdrom_match)) { + auto device_number = key.split("_").at(1); + auto cdrom_internal_name = QString(floppy_cdrom_config[key]); + auto cdrom_type = cdrom_get_from_internal_name(cdrom_internal_name.toUtf8().data()); + + auto cdrom_speed_key = QString("cdrom_%1_speed").arg(device_number); + auto cdrom_parameters_key = QString("cdrom_%1_parameters").arg(device_number); + auto cdrom_speed = QString(floppy_cdrom_config[cdrom_speed_key]); + auto cdrom_parameters = QString(floppy_cdrom_config[cdrom_parameters_key]); + auto cdrom_bus = cdrom_parameters.split(",").at(1).trimmed().toUpper(); + + if(cdrom_type != -1) { + if(!cdrom_speed.isEmpty()) { + cdrom_speed = QString("%1x ").arg(cdrom_speed); + } + if(!cdrom_bus.isEmpty()) { + cdrom_bus = QString(" (%1)").arg(cdrom_bus); + } + cdromDevices.append(QString("%1%2 %3 %4%5").arg(cdrom_speed, cdrom_drive_types[cdrom_type].vendor, cdrom_drive_types[cdrom_type].model, cdrom_drive_types[cdrom_type].revision, cdrom_bus)); + } + } + } + + display_table[Display::Name::Floppy] = floppyDevices.join(VMManagerDetailSection::sectionSeparator); + display_table[Display::Name::CD] = cdromDevices.join(VMManagerDetailSection::sectionSeparator); + + // SCSI controllers + QStringList scsiControllers; + static auto scsi_match = QRegularExpression("scsicard_\\d", QRegularExpression::CaseInsensitiveOption); + for(const auto& key: scsi_config.keys()) { + if(key.contains(scsi_match)) { + auto device_number = key.split("_").at(1); + auto scsi_internal_name = QString(scsi_config[key]); + auto scsi_id = scsi_card_get_from_internal_name(scsi_internal_name.toUtf8().data()); + auto scsi_device = scsi_card_getdevice(scsi_id); + auto scsi_name = QString(scsi_device->name); + if(!scsi_name.isEmpty()) { + scsiControllers.append(scsi_name); + } + } + } + display_table[Display::Name::SCSIController] = scsiControllers.join(VMManagerDetailSection::sectionSeparator); + + // Audio + int sound_int = sound_card_get_from_internal_name(audio_config["sndcard"].toUtf8().data()); + const device_t* audio_dev = sound_card_getdevice(sound_int); + display_table[Display::Name::Audio] = DeviceConfig::DeviceName(audio_dev, sound_card_get_internal_name(sound_int), 1); + + // MIDI + QString midiOutDev; + if(auto midi_out_device = QString(audio_config["midi_device"]); !midi_out_device.isEmpty()) { + auto midi_device_int = midi_out_device_get_from_internal_name(midi_out_device.toUtf8().data()); + auto midi_out = midi_out_device_getdevice(midi_device_int); + if(auto midiDevName = QString(midi_out->name); !midiDevName.isEmpty()) { + midiOutDev = midiDevName; + } + } + display_table[Display::Name::MidiOut] = midiOutDev; + + // midi_device = mt32 (output) + // mpu401_standalone = 1 + // midi_in_device (input) + + // Network + QString nicList; + static auto nic_match = QRegularExpression("net_\\d\\d_card", QRegularExpression::CaseInsensitiveOption); + for(const auto& key: network_config.keys()) { + if(key.contains(nic_match)) { + auto device_number = key.split("_").at(1); + auto nic_internal_name = QString(network_config[key]); + auto nic_id = network_card_get_from_internal_name(nic_internal_name.toUtf8().data()); + auto nic = network_card_getdevice(nic_id); + auto nic_name = QString(nic->name); + // Add separator for each subsequent value, skipping the first + if(!nicList.isEmpty()) { + nicList.append(QString("%1").arg(VMManagerDetailSection::sectionSeparator)); + } + auto net_type_key = QString("net_%1_net_type").arg(device_number); + auto net_type = network_config[net_type_key]; + if (!net_type.isEmpty()) { + nicList.append(nic_name + " (" + net_type + ")"); + } else { + nicList.append(nic_name); + } + + } + } + if(nicList.isEmpty()) { + nicList = "None"; + } + display_table[Display::Name::NIC] = nicList; + + // Input (Mouse) + auto mouse_internal_name = input_config["mouse_type"]; + auto mouse_dev = mouse_get_from_internal_name(mouse_internal_name.toUtf8().data()); + auto mouse_dev_name = mouse_get_name(mouse_dev); + display_table[Display::Name::Mouse] = mouse_dev_name; + + // Input (joystick) + QString joystickDevice; + if(auto joystick_internal = QString(input_config["joystick_type"]); !joystick_internal.isEmpty()) { + auto joystick_dev = joystick_get_from_internal_name(joystick_internal.toUtf8().data()); + if (auto joystickName = QString(joystick_get_name(joystick_dev)); !joystickName.isEmpty()) { + joystickDevice = joystickName; + } + } + display_table[Display::Name::Joystick] = joystickDevice; + + // # Ports + // Serial + // By default serial 1 and 2 are enabled unless otherwise specified + static auto serial_match = QRegularExpression("serial\\d_enabled", QRegularExpression::CaseInsensitiveOption); + QList serial_enabled = {true, true, false, false}; + // Parallel + // By default lpt 1 is enabled unless otherwise specified + static auto lpt_match = QRegularExpression("lpt\\d_enabled", QRegularExpression::CaseInsensitiveOption); + QList lpt_enabled = {true, false, false, false}; + for (const auto &key: ports_config.keys()) { + if (key.contains(serial_match)) { + if (auto serial_dev = key.split("_").at(0); !serial_dev.isEmpty()) { + auto serial_num = serial_dev.at(serial_dev.size() - 1); + // qDebug() << "serial is set" << key << ":" << ports_config[key]; + if(serial_num.isDigit() && serial_num.digitValue() >= 1 && serial_num.digitValue() <= 4) { + // Already verified that it is a digit with isDigit() + serial_enabled[serial_num.digitValue() - 1] = ports_config[key].toInt() == 1; + } + } + } + if (key.contains(lpt_match)) { + if (auto lpt_dev = key.split("_").at(0); !lpt_dev.isEmpty()) { + auto lpt_num = lpt_dev.at(lpt_dev.size() - 1); + // qDebug() << "lpt is set" << key << ":" << ports_config[key]; + if (lpt_num.isDigit() && lpt_num.digitValue() >= 1 && lpt_num.digitValue() <= 4) { + lpt_enabled[lpt_num.digitValue() - 1] = ports_config[key].toInt() == 1; + } + } + } + } + // qDebug() << "ports final" << serial_enabled << lpt_enabled; + QStringList serialFinal; + QStringList lptFinal; + int portIndex = 0; + while (true) { + if (serial_enabled[portIndex]) + serialFinal.append(QString("COM%1").arg(portIndex + 1)); + ++portIndex; + if (portIndex == SERIAL_MAX) + break; + } + portIndex = 0; + while (true) { + if (lpt_enabled[portIndex]) + lptFinal.append(QString("LPT%1").arg(portIndex + 1)); + ++portIndex; + if (portIndex == PARALLEL_MAX) + break; + } + display_table[Display::Name::Serial] = serialFinal.empty() ? tr("None") : serialFinal.join(", "); + display_table[Display::Name::Parallel] = lptFinal.empty() ? tr("None") : lptFinal.join(", "); + +} + +bool +VMManagerSystem::startServer() { + if (socket_server->startServer()) { + serverIsRunning = true; + connect(socket_server, &VMManagerServerSocket::dataReceived, this, &VMManagerSystem::dataReceived); + connect(socket_server, &VMManagerServerSocket::windowStatusChanged, this, &VMManagerSystem::windowStatusChangeReceived); + connect(socket_server, &VMManagerServerSocket::runningStatusChanged, this, &VMManagerSystem::runningStatusChangeReceived); + return true; + } else { + return false; + } +} + +void +VMManagerSystem::setProcessEnvVars() { + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + QString env_var_name = (socket_server_type == VMManagerServerSocket::ServerType::Standard) ? "VMM_86BOX_SOCKET" : "86BOX_MANAGER_SOCKET"; + env.insert(env_var_name, socket_server->getSocketPath()); + process->setProcessEnvironment(env); +} + +void +VMManagerSystem::restartButtonPressed() { + socket_server->serverSendMessage(VMManagerProtocol::ManagerMessage::ResetVM); + +} + +void +VMManagerSystem::pauseButtonPressed() { + socket_server->serverSendMessage(VMManagerProtocol::ManagerMessage::Pause); +} +void +VMManagerSystem::dataReceived() +{ + qInfo() << Q_FUNC_INFO << "Note: Respond to data received events here."; +} +void +VMManagerSystem::windowStatusChangeReceived(int status) +{ + window_obscured = status; + emit windowStatusChanged(); + processStatusChanged(); +} +QString +VMManagerSystem::getDisplayValue(Display::Name key) +{ + return (display_table.contains(key)) ? display_table[key] : ""; +} + +void +VMManagerSystem::shutdownRequestButtonPressed() +{ + socket_server->serverSendMessage(VMManagerProtocol::ManagerMessage::RequestShutdown); +} + +void +VMManagerSystem::shutdownForceButtonPressed() +{ + socket_server->serverSendMessage(VMManagerProtocol::ManagerMessage::ForceShutdown); +} + +void +VMManagerSystem::cadButtonPressed() +{ + socket_server->serverSendMessage(VMManagerProtocol::ManagerMessage::CtrlAltDel); +} + +void +VMManagerSystem::processStatusChanged() +{ + // set to running if the process is running and the state is stopped + if (process->state() == QProcess::ProcessState::Running) { + if (process_status == VMManagerSystem::ProcessStatus::Stopped) { + process_status = VMManagerSystem::ProcessStatus::Running; + } + } else if (process->state() == QProcess::ProcessState::NotRunning) { + process_status = VMManagerSystem::ProcessStatus::Stopped; + } + emit itemDataChanged(); + emit clientProcessStatusChanged(); +} +void +VMManagerSystem::statusRefresh() +{ + processStatusChanged(); +} +QString +VMManagerSystem::processStatusToString(VMManagerSystem::ProcessStatus status) +{ +// QMetaEnum qme = QMetaEnum::fromType(); +// return qme.valueToKey(static_cast(status)); + switch (status) { + case VMManagerSystem::ProcessStatus::Stopped: + return tr("Powered Off"); + case VMManagerSystem::ProcessStatus::Running: + return tr("Running"); + case VMManagerSystem::ProcessStatus::Paused: + return tr("Paused"); + case VMManagerSystem::ProcessStatus::PausedWaiting: + case VMManagerSystem::ProcessStatus::RunningWaiting: + return tr("Paused (Waiting)"); + default: + return tr("Unknown Status"); + } +} + +QString +VMManagerSystem::getProcessStatusString() const +{ + return processStatusToString(process_status); +} + +VMManagerSystem::ProcessStatus +VMManagerSystem::getProcessStatus() const +{ + return process_status; +} +// Maps VMManagerProtocol::RunningState to VMManagerSystem::ProcessStatus +void +VMManagerSystem::runningStatusChangeReceived(VMManagerProtocol::RunningState state) +{ + if(state == VMManagerProtocol::RunningState::Running) { + process_status = VMManagerSystem::ProcessStatus::Running; + } else if(state == VMManagerProtocol::RunningState::Paused) { + process_status = VMManagerSystem::ProcessStatus::Paused; + } else if(state == VMManagerProtocol::RunningState::RunningWaiting) { + process_status = VMManagerSystem::ProcessStatus::RunningWaiting; + } else if(state == VMManagerProtocol::RunningState::PausedWaiting) { + process_status = VMManagerSystem::ProcessStatus::PausedWaiting; + } else { + process_status = VMManagerSystem::ProcessStatus::Unknown; + } + processStatusChanged(); +} +void +VMManagerSystem::reloadConfig() +{ + loadSettings(); + setupVars(); +} + +QDateTime +VMManagerSystem::timestamp() +{ + return lastUsedTimestamp; +} +void +VMManagerSystem::setIcon(const QString &newIcon) +{ + icon = newIcon; + saveSettings(); + emit itemDataChanged(); +} diff --git a/src/qt/qt_vmmanager_system.hpp b/src/qt/qt_vmmanager_system.hpp new file mode 100644 index 000000000..ab2069617 --- /dev/null +++ b/src/qt/qt_vmmanager_system.hpp @@ -0,0 +1,191 @@ +/* +* 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. +* +* Header for 86Box VM manager system module +* +* +* +* Authors: cold-brewed +* +* Copyright 2024 cold-brewed +*/ + +#ifndef QT_VMMANAGER_SYSTEM_H +#define QT_VMMANAGER_SYSTEM_H + +#include +#include +#include +#include +#include +#include "qt_vmmanager_serversocket.hpp" +#include "qt_vmmanager_config.hpp" +#include "qt_deviceconfig.hpp" + +// This macro helps give us the required `qHash()` function in order to use the +// enum as a hash key +#define QHASH_FOR_CLASS_ENUM(T) \ +inline uint qHash(const T &t, uint seed) { \ + return ::qHash(static_cast::type>(t), seed); \ +} + +namespace Display { +Q_NAMESPACE +enum class Name { + Machine, + CPU, + Memory, + Video, + Disks, + Floppy, + CD, + SCSIController, + MidiOut, + Joystick, + Serial, + Parallel, + Audio, + Voodoo, + NIC, + Mouse, + Unknown +}; +Q_ENUM_NS(Name) +QHASH_FOR_CLASS_ENUM(Name) +} + +class VMManagerSystem : public QWidget { + Q_OBJECT + + typedef QHash display_table_t; + typedef QHash > config_hash_t; + +public: + + enum class ProcessStatus { + Stopped, + Running, + Paused, + PausedWaiting, + RunningWaiting, + Unknown, + }; + Q_ENUM(ProcessStatus); + + explicit VMManagerSystem(const QString &sysconfig_file); + // Default constructor will generate a temporary filename as the config file + // but it will not be valid (isValid() will return false) + VMManagerSystem() : VMManagerSystem(generateTemporaryFilename()) {} + + ~VMManagerSystem() override; + + static QVector scanForConfigs(QWidget* parent = nullptr, const QString &searchPath = {}); + static QString generateTemporaryFilename(); + + QFileInfo config_file; + QString config_name; + QString config_dir; + QString shortened_dir; + QString uuid; + QString displayName; + QString notes; + QString icon; + QStringList searchTerms; + + config_hash_t config_hash; + + [[nodiscard]] QString getAll(const QString& category) const; + [[nodiscard]] QHash getCategory(const QString& category) const; + [[nodiscard]] QHash > getConfigHash() const; + + void setDisplayName(const QString& newDisplayName); + void setNotes(const QString& newNotes); + + [[nodiscard]] bool isValid() const; + [[nodiscard]] bool isProcessRunning() const; + [[nodiscard]] qint64 processId() const; +public slots: + void launchMainProcess(); + void launchSettings(); + void startButtonPressed(); + void restartButtonPressed(); + void pauseButtonPressed(); + void shutdownRequestButtonPressed(); + void shutdownForceButtonPressed(); + void cadButtonPressed(); + void reloadConfig(); +public: + QDateTime timestamp(); + void setIcon(const QString &newIcon); + + QProcess *process = new QProcess(); + + bool window_obscured; + + QString getDisplayValue(Display::Name key); + QFileInfoList getScreenshots(); + + inline bool operator==(const VMManagerSystem &rhs) const + { + return config_file.filePath() == rhs.config_file.filePath(); + } + + static QString + processStatusToString(VMManagerSystem::ProcessStatus status) ; + ProcessStatus process_status; + [[nodiscard]] QString getProcessStatusString() const; + [[nodiscard]] ProcessStatus getProcessStatus() const; + +signals: + void windowStatusChanged(); + void itemDataChanged(); + void clientProcessStatusChanged(); + +private: + void loadSettings(); + void saveSettings(); + void generateSearchTerms(); + void updateTimestamp(); + + display_table_t display_table; + + QFileInfo main_binary; + QString platform; + + // QDir application_temp_directory; + // QDir standard_temp_directory; + // QDir app_data_directory; + QDir screenshot_directory; + + QString unique_name; + QDateTime lastUsedTimestamp; + + VMManagerServerSocket *socket_server; + VMManagerServerSocket::ServerType socket_server_type; + + // Configuration file settings + VMManagerConfig *config_settings; + + bool serverIsRunning; + bool startServer(); + + bool has86BoxBinary(); + void find86BoxBinary(); + void setupPaths(); + void setupVars(); + void setProcessEnvVars(); + + void dataReceived(); + void windowStatusChangeReceived(int status); + void runningStatusChangeReceived(VMManagerProtocol::RunningState state); + void processStatusChanged(); + void statusRefresh(); +}; + + +#endif //QT_VMMANAGER_SYSTEM_H diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index a5963c152..51518b8f6 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -59,4 +59,95 @@ qt/texture_vert.spv qt/texture_frag.spv + + qt/assets/86Box-green.png + qt/assets/86box-rb.png + qt/assets/86box-red.png + qt/assets/86box-yellow.png + qt/assets/86box.png + qt/assets/86box-wizard.png + + + qt/assets/systemicons/cpq_deskpro.png + qt/assets/systemicons/cpq_port_386.png + qt/assets/systemicons/cpq_port_II.png + qt/assets/systemicons/cpq_port_III.png + qt/assets/systemicons/cpq_portable.png + qt/assets/systemicons/cpq_pres_2240.png + qt/assets/systemicons/cpq_pres_4500.png + qt/assets/systemicons/ibm330.png + qt/assets/systemicons/ibm_at.png + qt/assets/systemicons/ibm_pc_81.png + qt/assets/systemicons/ibm_pc_82.png + qt/assets/systemicons/ibm_pcjr.png + qt/assets/systemicons/ibm_ps2_m70.png + qt/assets/systemicons/ibm_ps2_m80.png + qt/assets/systemicons/ibm_psvp_486.png + qt/assets/systemicons/ibm_psvp_p60.png + qt/assets/systemicons/ibm_xt_82.png + qt/assets/systemicons/ibm_xt_86.png + qt/assets/systemicons/olivetti_m19.png + qt/assets/systemicons/olivetti_m21.png + qt/assets/systemicons/olivetti_m24.png + qt/assets/systemicons/olivetti_m24sp.png + qt/assets/systemicons/os_archlinux_x2.png + qt/assets/systemicons/os_cloud_x2.png + qt/assets/systemicons/os_debian_x2.png + qt/assets/systemicons/os_dos_x2.png + qt/assets/systemicons/os_fedora_x2.png + qt/assets/systemicons/os_freebsd_x2.png + qt/assets/systemicons/os_gentoo_x2.png + qt/assets/systemicons/os_jrockitve_x2.png + qt/assets/systemicons/os_l4_x2.png + qt/assets/systemicons/os_linux22_x2.png + qt/assets/systemicons/os_linux24_x2.png + qt/assets/systemicons/os_linux26_x2.png + qt/assets/systemicons/os_linux_x2.png + qt/assets/systemicons/os_macosx_x2.png + qt/assets/systemicons/os_mandriva_x2.png + qt/assets/systemicons/os_netbsd_x2.png + qt/assets/systemicons/os_netware_x2.png + qt/assets/systemicons/os_openbsd_x2.png + qt/assets/systemicons/os_opensuse_x2.png + qt/assets/systemicons/os_oracle_x2.png + qt/assets/systemicons/os_oraclesolaris_x2.png + qt/assets/systemicons/os_os2_other_x2.png + qt/assets/systemicons/os_os2ecs_x2.png + qt/assets/systemicons/os_os2warp3_x2.png + qt/assets/systemicons/os_os2warp45_x2.png + qt/assets/systemicons/os_os2warp4_x2.png + qt/assets/systemicons/os_other_x2.png + qt/assets/systemicons/os_qnx_x2.png + qt/assets/systemicons/os_redhat_x2.png + qt/assets/systemicons/os_solaris_x2.png + qt/assets/systemicons/os_turbolinux_x2.png + qt/assets/systemicons/os_ubuntu_x2.png + qt/assets/systemicons/os_win10_x2.png + qt/assets/systemicons/os_win2k3_x2.png + qt/assets/systemicons/os_win2k8_x2.png + qt/assets/systemicons/os_win2k_x2.png + qt/assets/systemicons/os_win31_x2.png + qt/assets/systemicons/os_win7_x2.png + qt/assets/systemicons/os_win81_x2.png + qt/assets/systemicons/os_win8_x2.png + qt/assets/systemicons/os_win95_x2.png + qt/assets/systemicons/os_win98_x2.png + qt/assets/systemicons/os_win_other_x2.png + qt/assets/systemicons/os_winme_x2.png + qt/assets/systemicons/os_winnt4_x2.png + qt/assets/systemicons/os_winvista_x2.png + qt/assets/systemicons/os_winxp_x2.png + qt/assets/systemicons/os_xandros_x2.png + qt/assets/systemicons/pb_bora_pro.png + qt/assets/systemicons/pb_pb410.png + qt/assets/systemicons/pb_pb640.png + qt/assets/systemicons/pb_pb680.png + qt/assets/systemicons/tandy_1000.png + qt/assets/systemicons/tandy_1000_hx.png + qt/assets/systemicons/tandy_1000_sl2.png + qt/assets/systemicons/toshiba_t1000.png + qt/assets/systemicons/toshiba_t1200.png + qt/assets/systemicons/toshiba_t1200_hdd.png + + diff --git a/src/sio/sio_um8663f.c b/src/sio/sio_um8663f.c index 54f12dda6..6075fe3e7 100644 --- a/src/sio/sio_um8663f.c +++ b/src/sio/sio_um8663f.c @@ -274,13 +274,70 @@ um8663f_init(UNUSED(const device_t *info)) dev->max_reg = info->local >> 8; - io_sethandler(0x0108, 0x0002, um8663f_read, NULL, NULL, um8663f_write, NULL, NULL, dev); + if (dev->max_reg != 0x00) + io_sethandler(0x0108, 0x0002, um8663f_read, NULL, NULL, um8663f_write, NULL, NULL, dev); um8663f_reset(dev); return dev; } +const device_t um82c862f_device = { + .name = "UMC UM82C862F Super I/O", + .internal_name = "um82c862f", + .flags = 0, + .local = 0x0000, + .init = um8663f_init, + .close = um8663f_close, + .reset = um8663f_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t um82c862f_ide_device = { + .name = "UMC UM82C862F Super I/O (With IDE)", + .internal_name = "um82c862f_ide", + .flags = 0, + .local = 0x0001, + .init = um8663f_init, + .close = um8663f_close, + .reset = um8663f_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t um82c863f_device = { + .name = "UMC UM82C863F Super I/O", + .internal_name = "um82c863f", + .flags = 0, + .local = 0xc100, + .init = um8663f_init, + .close = um8663f_close, + .reset = um8663f_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +const device_t um82c863f_ide_device = { + .name = "UMC UM82C863F Super I/O (With IDE)", + .internal_name = "um82c863f_ide", + .flags = 0, + .local = 0xc101, + .init = um8663f_init, + .close = um8663f_close, + .reset = um8663f_reset, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + const device_t um8663af_device = { .name = "UMC UM8663AF Super I/O", .internal_name = "um8663af", diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt index 2e6d3af08..6f9693e5a 100644 --- a/src/video/CMakeLists.txt +++ b/src/video/CMakeLists.txt @@ -11,80 +11,133 @@ # Authors: David Hrdlička, # # Copyright 2020-2021 David Hrdlička. -# Copyright 2025 Connor Hyde +# Copyright 2025 Connor Hyde / starfrost # -# todo: Split nv stuff into its own file... - add_library(vid OBJECT + + # Video Core agpgart.c video.c vid_table.c + + # RAMDAC (Should this be its own library?) + ramdac/vid_ramdac_ati68860.c + ramdac/vid_ramdac_ati68875.c + ramdac/vid_ramdac_att20c49x.c + ramdac/vid_ramdac_att2xc498.c + ramdac/vid_ramdac_bt48x.c + ramdac/vid_ramdac_bt481.c + ramdac/vid_ramdac_ibm_rgb528.c + ramdac/vid_ramdac_sc1148x.c + ramdac/vid_ramdac_sc1502x.c + ramdac/vid_ramdac_sdac.c + ramdac/vid_ramdac_stg1702.c + ramdac/vid_ramdac_tkd8001.c + ramdac/vid_ramdac_tvp3026.c + + # Clock generator chips + clockgen/vid_clockgen_av9194.c + clockgen/vid_clockgen_icd2061.c + clockgen/vid_clockgen_ics2494.c + clockgen/vid_clockgen_ics2595.c + + # DDC / monitor identification stuff + vid_ddc.c + + # CARDS start here + + # CGA / Super CGA vid_cga.c vid_cga_comp.c - vid_compaq_cga.c + vid_cga_compaq.c + vid_cga_compaq_plasma.c + vid_cga_colorplus.c + vid_cga_ncr.c + vid_cga_olivetti.c + vid_cga_toshiba_t1000.c + vid_cga_toshiba_t3100e.c + + # PCJr/Tandy + vid_pcjr.c + vid_tandy.c vid_mda.c + + # Hercules vid_hercules.c - vid_herculesplus.c - vid_incolor.c - vid_colorplus.c + vid_hercules_plus.c + vid_hercules_incolor.c + + # Other early CGA-era cards vid_genius.c + vid_sigma.c + + # PGC / IM1024 / WY700 high-resolution vid_pgc.c vid_im1024.c - vid_sigma.c vid_wy700.c + + # EGA vid_ega.c vid_ega_render.c - vid_svga.c - vid_8514a.c - vid_svga_render.c - vid_ddc.c + vid_jega.c + + # (Real IBM) VGA vid_vga.c + + # Super VGA core + vid_svga.c + vid_svga_render.c + + # 8514/A, XGA and derivatives + vid_8514a.c + vid_xga.c + vid_ps55da2.c + + # ATI Technologies vid_ati_eeprom.c vid_ati18800.c vid_ati28800.c vid_ati_mach8.c vid_ati_mach64.c - vid_ati68875_ramdac.c - vid_ati68860_ramdac.c - vid_bt481_ramdac.c - vid_bt48x_ramdac.c + + # Chips & Technologies vid_chips_69000.c - vid_av9194.c - vid_icd2061.c - vid_ics2494.c - vid_ics2595.c + + # Cirrus Logic vid_cl54xx.c + + # Tseng Labs vid_et3000.c vid_et4000.c - vid_sc1148x_ramdac.c - vid_sc1502x_ramdac.c vid_et4000w32.c - vid_stg_ramdac.c + + # Headland vid_ht216.c vid_oak_oti.c + + # Paradise vid_paradise.c vid_rtg310x.c vid_f82c425.c vid_ti_cf62011.c - vid_tvga.c vid_tgui9440.c - vid_tkd8001_ramdac.c - vid_att20c49x_ramdac.c - vid_s3.c vid_s3_virge.c - vid_ibm_rgb528_ramdac.c - vid_sdac_ramdac.c - vid_ogc.c - vid_mga.c - vid_nga.c - vid_tvp3026_ramdac.c - vid_att2xc498_ramdac.c - vid_xga.c - vid_bochs_vbe.c - vid_ps55da2.c - vid_jega.c - nv/nv_base.c nv/nv_rivatimer.c - + # Trident + vid_tvga.c + vid_tgui9440.c + + # S3 Graphics + vid_s3.c + vid_s3_virge.c + + # Matrox + vid_mga.c + + # NVidia - Core + nv/nv_base.c + nv/nv_rivatimer.c + + # NVidia RIVA 128 - Subsystems nv/nv3/nv3_core.c nv/nv3/nv3_core_config.c nv/nv3/nv3_core_arbiter.c @@ -96,12 +149,17 @@ add_library(vid OBJECT nv/nv3/subsystems/nv3_pme.c nv/nv3/subsystems/nv3_pextdev.c nv/nv3/subsystems/nv3_pfb.c - nv/nv3/subsystems/nv3_pbus.c nv/nv3/subsystems/nv3_pbus_dma.c + nv/nv3/subsystems/nv3_pbus.c + nv/nv3/subsystems/nv3_pbus_dma.c nv/nv3/subsystems/nv3_ptimer.c - nv/nv3/subsystems/nv3_pramin.c nv/nv3/subsystems/nv3_pramin_ramht.c nv/nv3/subsystems/nv3_pramin_ramfc.c nv/nv3/subsystems/nv3_pramin_ramro.c + nv/nv3/subsystems/nv3_pramin.c + nv/nv3/subsystems/nv3_pramin_ramht.c + nv/nv3/subsystems/nv3_pramin_ramfc.c + nv/nv3/subsystems/nv3_pramin_ramro.c nv/nv3/subsystems/nv3_pvideo.c nv/nv3/subsystems/nv3_user.c + # NVidia RIVA 128 - Object Classes nv/nv3/classes/nv3_class_names.c nv/nv3/classes/nv3_class_shared_methods.c nv/nv3/classes/nv3_class_001_beta_factor.c @@ -127,10 +185,14 @@ add_library(vid OBJECT nv/nv3/classes/nv3_class_018_point_zeta_buffer.c nv/nv3/classes/nv3_class_01c_image_in_memory.c + # NVidia RIVA 128 - Render nv/nv3/render/nv3_render_core.c nv/nv3/render/nv3_render_primitives.c - nv/nv3/render/nv3_render_blit.c - + nv/nv3/render/nv3_render_blit.c + + # Generic + vid_bochs_vbe.c + ) if(G100) @@ -141,6 +203,7 @@ if(XL24) target_compile_definitions(vid PRIVATE USE_XL24) endif() +# 3Dfx Voodoo add_library(voodoo OBJECT vid_voodoo.c vid_voodoo_banshee.c diff --git a/src/video/vid_av9194.c b/src/video/clockgen/vid_clockgen_av9194.c similarity index 100% rename from src/video/vid_av9194.c rename to src/video/clockgen/vid_clockgen_av9194.c diff --git a/src/video/vid_icd2061.c b/src/video/clockgen/vid_clockgen_icd2061.c similarity index 100% rename from src/video/vid_icd2061.c rename to src/video/clockgen/vid_clockgen_icd2061.c diff --git a/src/video/vid_ics2494.c b/src/video/clockgen/vid_clockgen_ics2494.c similarity index 100% rename from src/video/vid_ics2494.c rename to src/video/clockgen/vid_clockgen_ics2494.c diff --git a/src/video/vid_ics2595.c b/src/video/clockgen/vid_clockgen_ics2595.c similarity index 100% rename from src/video/vid_ics2595.c rename to src/video/clockgen/vid_clockgen_ics2595.c diff --git a/src/video/vid_ati68860_ramdac.c b/src/video/ramdac/vid_ramdac_ati68860.c similarity index 84% rename from src/video/vid_ati68860_ramdac.c rename to src/video/ramdac/vid_ramdac_ati68860.c index 17b2a6d22..e3e486d57 100644 --- a/src/video/vid_ati68860_ramdac.c +++ b/src/video/ramdac/vid_ramdac_ati68860.c @@ -261,38 +261,57 @@ void ati68860_hwcursor_draw(svga_t *svga, int displine) { const ati68860_ramdac_t *ramdac = (ati68860_ramdac_t *) svga->ramdac; + int comb; int offset; - uint8_t dat; + int x_pos; + int y_pos; + int shift = 0; + uint16_t dat; uint32_t col0 = ramdac->pallook[0]; uint32_t col1 = ramdac->pallook[1]; + uint32_t *p; - offset = svga->dac_hwcursor_latch.xoff; - for (uint32_t x = 0; x < 64 - svga->dac_hwcursor_latch.xoff; x += 4) { - dat = svga->vram[svga->dac_hwcursor_latch.addr + (offset >> 2)]; - if (!(dat & 2)) - buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) - buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add] ^= 0xFFFFFF; - dat >>= 2; - if (!(dat & 2)) - buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 1] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) - buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 1] ^= 0xFFFFFF; - dat >>= 2; - if (!(dat & 2)) - buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 2] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) - buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 2] ^= 0xFFFFFF; - dat >>= 2; - if (!(dat & 2)) - buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 3] = (dat & 1) ? col1 : col0; - else if ((dat & 3) == 3) - buffer32->line[displine][svga->dac_hwcursor_latch.x + x + svga->x_add + 3] ^= 0xFFFFFF; - dat >>= 2; - offset += 4; + offset = svga->dac_hwcursor_latch.x - svga->dac_hwcursor_latch.xoff; + if (svga->packed_4bpp) + shift = 1; + + for (int x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += (8 >> shift)) { + if (shift) { + dat = svga->vram[(svga->dac_hwcursor_latch.addr) & svga->vram_mask] & 0x0f; + dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 1) & svga->vram_mask] << 4); + dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 2) & svga->vram_mask] << 8); + dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 3) & svga->vram_mask] << 12); + } else { + dat = svga->vram[svga->dac_hwcursor_latch.addr & svga->vram_mask]; + dat |= (svga->vram[(svga->dac_hwcursor_latch.addr + 1) & svga->vram_mask] << 8); + } + for (int xx = 0; xx < (8 >> shift); xx++) { + comb = (dat >> (xx << 1)) & 0x03; + + y_pos = displine; + x_pos = offset + svga->x_add; + p = buffer32->line[y_pos]; + + if (offset >= svga->dac_hwcursor_latch.x) { + switch (comb) { + case 0: + p[x_pos] = col0; + break; + case 1: + p[x_pos] = col1; + break; + case 3: + p[x_pos] ^= 0xffffff; + break; + + default: + break; + } + } + offset++; + } + svga->dac_hwcursor_latch.addr += 2; } - - svga->dac_hwcursor_latch.addr += 16; } static void diff --git a/src/video/vid_ati68875_ramdac.c b/src/video/ramdac/vid_ramdac_ati68875.c similarity index 100% rename from src/video/vid_ati68875_ramdac.c rename to src/video/ramdac/vid_ramdac_ati68875.c diff --git a/src/video/vid_att20c49x_ramdac.c b/src/video/ramdac/vid_ramdac_att20c49x.c similarity index 100% rename from src/video/vid_att20c49x_ramdac.c rename to src/video/ramdac/vid_ramdac_att20c49x.c diff --git a/src/video/vid_att2xc498_ramdac.c b/src/video/ramdac/vid_ramdac_att2xc498.c similarity index 100% rename from src/video/vid_att2xc498_ramdac.c rename to src/video/ramdac/vid_ramdac_att2xc498.c diff --git a/src/video/vid_bt481_ramdac.c b/src/video/ramdac/vid_ramdac_bt481.c similarity index 100% rename from src/video/vid_bt481_ramdac.c rename to src/video/ramdac/vid_ramdac_bt481.c diff --git a/src/video/vid_bt48x_ramdac.c b/src/video/ramdac/vid_ramdac_bt48x.c similarity index 100% rename from src/video/vid_bt48x_ramdac.c rename to src/video/ramdac/vid_ramdac_bt48x.c diff --git a/src/video/vid_ibm_rgb528_ramdac.c b/src/video/ramdac/vid_ramdac_ibm_rgb528.c similarity index 91% rename from src/video/vid_ibm_rgb528_ramdac.c rename to src/video/ramdac/vid_ramdac_ibm_rgb528.c index dcdbbb25b..cd7d5c1b6 100644 --- a/src/video/vid_ibm_rgb528_ramdac.c +++ b/src/video/ramdac/vid_ramdac_ibm_rgb528.c @@ -104,7 +104,7 @@ ibm_rgb528_render_4bpp(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -114,8 +114,8 @@ ibm_rgb528_render_4bpp(svga_t *svga) for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { if (vram_size == 3) { if (!(x & 31)) { - dat64 = *(uint64_t *) (&svga->vram[svga->ma]); - dat642 = *(uint64_t *) (&svga->vram[svga->ma + 8]); + dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]); + dat642 = *(uint64_t *) (&svga->vram[svga->memaddr + 8]); if (swap_word) { dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); @@ -127,7 +127,7 @@ ibm_rgb528_render_4bpp(svga_t *svga) dat = (((x & 16) ? dat642 : dat64) >> (((x & 15) << 2) ^ 4)) & 0xf; } else if (vram_size == 1) { if (!(x & 15)) { - dat64 = *(uint64_t *) (&svga->vram[svga->ma]); + dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]); if (swap_word) dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); } @@ -137,7 +137,7 @@ ibm_rgb528_render_4bpp(svga_t *svga) dat = (dat64 >> (((x & 15) << 2) ^ 4)) & 0xf; } else { if (!(x & 7)) - dat32 = *(uint32_t *) (&svga->vram[svga->ma]); + dat32 = *(uint32_t *) (&svga->vram[svga->memaddr]); if (swap_nib) dat = (dat32 >> ((x & 7) << 2)) & 0xf; else @@ -156,11 +156,11 @@ ibm_rgb528_render_4bpp(svga_t *svga) p[x] = dat_out.pixel & 0xffffff; if ((vram_size == 3) && ((x & 31) == 31)) - svga->ma = (svga->ma + 16) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 16) & svga->vram_display_mask; if ((vram_size == 1) && ((x & 15) == 15)) - svga->ma = (svga->ma + 8) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 8) & svga->vram_display_mask; else if ((!vram_size) && ((x & 7) == 7)) - svga->ma = (svga->ma + 4) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 4) & svga->vram_display_mask; } } } @@ -182,7 +182,7 @@ ibm_rgb528_render_8bpp(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -192,8 +192,8 @@ ibm_rgb528_render_8bpp(svga_t *svga) for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { if (vram_size == 3) { if (!(x & 15)) { - dat64 = *(uint64_t *) (&svga->vram[svga->ma]); - dat642 = *(uint64_t *) (&svga->vram[svga->ma + 8]); + dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]); + dat642 = *(uint64_t *) (&svga->vram[svga->memaddr + 8]); if (swap_word) { dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); @@ -202,14 +202,14 @@ ibm_rgb528_render_8bpp(svga_t *svga) dat = (((x & 8) ? dat642 : dat64) >> ((x & 7) << 3)) & 0xff; } else if (vram_size == 1) { if (!(x & 7)) { - dat64 = *(uint64_t *) (&svga->vram[svga->ma]); + dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]); if (swap_word) dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); } dat = (dat64 >> ((x & 7) << 3)) & 0xff; } else { if (!(x & 3)) - dat32 = *(uint32_t *) (&svga->vram[svga->ma]); + dat32 = *(uint32_t *) (&svga->vram[svga->memaddr]); dat = (dat32 >> ((x & 3) << 3)) & 0xff; } if (b8_dcol == 0x00) { @@ -225,11 +225,11 @@ ibm_rgb528_render_8bpp(svga_t *svga) p[x] = dat_out.pixel & 0xffffff; if ((vram_size == 3) && ((x & 15) == 15)) - svga->ma = (svga->ma + 16) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 16) & svga->vram_display_mask; else if ((vram_size == 1) && ((x & 7) == 7)) - svga->ma = (svga->ma + 8) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 8) & svga->vram_display_mask; else if ((!vram_size) && ((x & 3) == 3)) - svga->ma = (svga->ma + 4) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 4) & svga->vram_display_mask; } } } @@ -262,7 +262,7 @@ ibm_rgb528_render_15_16bpp(svga_t *svga) if (b555_565 && (b16_dcol != 0x01)) partition &= 0xc0; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -272,8 +272,8 @@ ibm_rgb528_render_15_16bpp(svga_t *svga) for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { if (vram_size == 2) { if (!(x & 7)) { - dat64 = *(uint64_t *) (&svga->vram[svga->ma]); - dat642 = *(uint64_t *) (&svga->vram[svga->ma + 8]); + dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]); + dat642 = *(uint64_t *) (&svga->vram[svga->memaddr + 8]); if (swap_word) { dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); dat642 = (dat64 << 32ULL) | (dat642 >> 32ULL); @@ -282,14 +282,14 @@ ibm_rgb528_render_15_16bpp(svga_t *svga) dat = (((x & 4) ? dat642 : dat64) >> ((x & 3) << 4)) & 0xffff; } else if (vram_size == 1) { if (!(x & 3)) { - dat64 = *(uint64_t *) (&svga->vram[svga->ma]); + dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]); if (swap_word) dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); } dat = (dat64 >> ((x & 3) << 4)) & 0xffff; } else { if (!(x & 1)) - dat32 = *(uint32_t *) (&svga->vram[svga->ma]); + dat32 = *(uint32_t *) (&svga->vram[svga->memaddr]); dat = (dat32 >> ((x & 1) << 4)) & 0xffff; } dat_ex = (ibm_rgb528_pixel16_t *) &dat; @@ -350,11 +350,11 @@ ibm_rgb528_render_15_16bpp(svga_t *svga) p[x] = dat_out.pixel & 0xffffff; if ((vram_size == 3) && ((x & 7) == 7)) - svga->ma = (svga->ma + 16) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 16) & svga->vram_display_mask; else if ((vram_size == 1) && ((x & 3) == 3)) - svga->ma = (svga->ma + 8) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 8) & svga->vram_display_mask; else if (!vram_size && ((x & 1) == 1)) - svga->ma = (svga->ma + 4) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 4) & svga->vram_display_mask; } } } @@ -378,7 +378,7 @@ ibm_rgb528_render_24bpp(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -389,12 +389,12 @@ ibm_rgb528_render_24bpp(svga_t *svga) dat_ex = (ibm_rgb528_pixel32_t *) &dat; if (vram_size == 3) { if ((x & 15) == 0) { - dat64[0] = *(uint64_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); - dat64[1] = *(uint64_t *) (&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); - dat64[2] = *(uint64_t *) (&svga->vram[(svga->ma + 16) & svga->vram_display_mask]); - dat64[3] = *(uint64_t *) (&svga->vram[(svga->ma + 24) & svga->vram_display_mask]); - dat64[4] = *(uint64_t *) (&svga->vram[(svga->ma + 32) & svga->vram_display_mask]); - dat64[5] = *(uint64_t *) (&svga->vram[(svga->ma + 40) & svga->vram_display_mask]); + dat64[0] = *(uint64_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); + dat64[1] = *(uint64_t *) (&svga->vram[(svga->memaddr + 8) & svga->vram_display_mask]); + dat64[2] = *(uint64_t *) (&svga->vram[(svga->memaddr + 16) & svga->vram_display_mask]); + dat64[3] = *(uint64_t *) (&svga->vram[(svga->memaddr + 24) & svga->vram_display_mask]); + dat64[4] = *(uint64_t *) (&svga->vram[(svga->memaddr + 32) & svga->vram_display_mask]); + dat64[5] = *(uint64_t *) (&svga->vram[(svga->memaddr + 40) & svga->vram_display_mask]); if (swap_word) { dat64[0] = (dat64[0] << 32ULL) | (dat64[0] >> 32ULL); dat64[1] = (dat64[1] << 32ULL) | (dat64[1] >> 32ULL); @@ -407,9 +407,9 @@ ibm_rgb528_render_24bpp(svga_t *svga) dat_ex = (ibm_rgb528_pixel32_t *) &(dat8[(x & 15) * 3]); } else if (vram_size == 1) { if ((x & 7) == 0) { - dat64[0] = *(uint64_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); - dat64[1] = *(uint64_t *) (&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); - dat64[2] = *(uint64_t *) (&svga->vram[(svga->ma + 16) & svga->vram_display_mask]); + dat64[0] = *(uint64_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); + dat64[1] = *(uint64_t *) (&svga->vram[(svga->memaddr + 8) & svga->vram_display_mask]); + dat64[2] = *(uint64_t *) (&svga->vram[(svga->memaddr + 16) & svga->vram_display_mask]); if (swap_word) { dat64[0] = (dat64[0] << 32ULL) | (dat64[0] >> 32ULL); dat64[1] = (dat64[1] << 32ULL) | (dat64[1] >> 32ULL); @@ -441,9 +441,9 @@ ibm_rgb528_render_24bpp(svga_t *svga) p[x] = dat_ex->pixel & 0xffffff; if ((vram_size == 3) && ((x & 15) == 15)) - svga->ma = (svga->ma + 48) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 48) & svga->vram_display_mask; else if ((vram_size == 1) && ((x & 7) == 7)) - svga->ma = (svga->ma + 24) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 24) & svga->vram_display_mask; } } } @@ -468,7 +468,7 @@ ibm_rgb528_render_32bpp(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) { p = &buffer32->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -478,8 +478,8 @@ ibm_rgb528_render_32bpp(svga_t *svga) for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { if (vram_size == 3) { if (!(x & 3)) { - dat64 = *(uint64_t *) (&svga->vram[svga->ma]); - dat642 = *(uint64_t *) (&svga->vram[svga->ma + 8]); + dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]); + dat642 = *(uint64_t *) (&svga->vram[svga->memaddr + 8]); if (swap_word) { dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); dat642 = (dat642 << 32ULL) | (dat642 >> 32ULL); @@ -488,13 +488,13 @@ ibm_rgb528_render_32bpp(svga_t *svga) dat = (((x & 2) ? dat642 : dat64) >> ((x & 1ULL) << 5ULL)) & 0xffffffff; } else if (vram_size == 1) { if (!(x & 1)) { - dat64 = *(uint64_t *) (&svga->vram[svga->ma]); + dat64 = *(uint64_t *) (&svga->vram[svga->memaddr]); if (swap_word) dat64 = (dat64 << 32ULL) | (dat64 >> 32ULL); } dat = (dat64 >> ((x & 1ULL) << 5ULL)) & 0xffffffff; } else - dat = *(uint32_t *) (&svga->vram[svga->ma]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr]); dat_ex = (ibm_rgb528_pixel32_t *) &dat; if (swaprb) { temp = dat_ex->r; @@ -520,11 +520,11 @@ ibm_rgb528_render_32bpp(svga_t *svga) p[x] = dat_ex->pixel & 0xffffff; if ((vram_size == 3) && ((x & 3) == 3)) - svga->ma = (svga->ma + 16) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 16) & svga->vram_display_mask; else if ((vram_size == 1) && ((x & 1) == 1)) - svga->ma = (svga->ma + 8) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 8) & svga->vram_display_mask; else if (!vram_size) - svga->ma = (svga->ma + 4) & svga->vram_display_mask; + svga->memaddr = (svga->memaddr + 4) & svga->vram_display_mask; } } } diff --git a/src/video/vid_sc1148x_ramdac.c b/src/video/ramdac/vid_ramdac_sc1148x.c similarity index 100% rename from src/video/vid_sc1148x_ramdac.c rename to src/video/ramdac/vid_ramdac_sc1148x.c diff --git a/src/video/vid_sc1502x_ramdac.c b/src/video/ramdac/vid_ramdac_sc1502x.c similarity index 100% rename from src/video/vid_sc1502x_ramdac.c rename to src/video/ramdac/vid_ramdac_sc1502x.c diff --git a/src/video/vid_sdac_ramdac.c b/src/video/ramdac/vid_ramdac_sdac.c similarity index 100% rename from src/video/vid_sdac_ramdac.c rename to src/video/ramdac/vid_ramdac_sdac.c diff --git a/src/video/vid_stg_ramdac.c b/src/video/ramdac/vid_ramdac_stg1702.c similarity index 100% rename from src/video/vid_stg_ramdac.c rename to src/video/ramdac/vid_ramdac_stg1702.c diff --git a/src/video/vid_tkd8001_ramdac.c b/src/video/ramdac/vid_ramdac_tkd8001.c similarity index 100% rename from src/video/vid_tkd8001_ramdac.c rename to src/video/ramdac/vid_ramdac_tkd8001.c diff --git a/src/video/vid_tvp3026_ramdac.c b/src/video/ramdac/vid_ramdac_tvp3026.c similarity index 100% rename from src/video/vid_tvp3026_ramdac.c rename to src/video/ramdac/vid_ramdac_tvp3026.c diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index 02f22ed54..97202340d 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -459,7 +459,7 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) break; case 0x42e8: - ibm8514_log("VBLANK stat=%02x, val=%02x.\n", dev->subsys_stat, val); + ibm8514_log("VBLANK status=%02x, val=%02x.\n", dev->subsys_stat, val); if (len == 2) { dev->subsys_cntl = val; dev->subsys_stat &= ~val; @@ -3383,7 +3383,7 @@ ibm8514_render_8bpp(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -3391,22 +3391,22 @@ ibm8514_render_8bpp(svga_t *svga) dev->lastline_draw = dev->displine; for (int x = 0; x <= dev->h_disp; x += 8) { - dat = *(uint32_t *) (&dev->vram[dev->ma & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[dev->memaddr & dev->vram_mask]); p[0] = dev->pallook[dat & dev->dac_mask & 0xff]; p[1] = dev->pallook[(dat >> 8) & dev->dac_mask & 0xff]; p[2] = dev->pallook[(dat >> 16) & dev->dac_mask & 0xff]; p[3] = dev->pallook[(dat >> 24) & dev->dac_mask & 0xff]; - dat = *(uint32_t *) (&dev->vram[(dev->ma + 4) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 4) & dev->vram_mask]); p[4] = dev->pallook[dat & dev->dac_mask & 0xff]; p[5] = dev->pallook[(dat >> 8) & dev->dac_mask & 0xff]; p[6] = dev->pallook[(dat >> 16) & dev->dac_mask & 0xff]; p[7] = dev->pallook[(dat >> 24) & dev->dac_mask & 0xff]; - dev->ma += 8; + dev->memaddr += 8; p += 8; } - dev->ma &= dev->vram_mask; + dev->memaddr &= dev->vram_mask; } } @@ -3421,7 +3421,7 @@ ibm8514_render_15bpp(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -3429,24 +3429,24 @@ ibm8514_render_15bpp(svga_t *svga) dev->lastline_draw = dev->displine; for (x = 0; x <= dev->h_disp; x += 8) { - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 1)) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 1)) & dev->vram_mask]); p[x] = video_15to32[dat & 0xffff]; p[x + 1] = video_15to32[dat >> 16]; - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 1) + 4) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 1) + 4) & dev->vram_mask]); p[x + 2] = video_15to32[dat & 0xffff]; p[x + 3] = video_15to32[dat >> 16]; - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 1) + 8) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 1) + 8) & dev->vram_mask]); p[x + 4] = video_15to32[dat & 0xffff]; p[x + 5] = video_15to32[dat >> 16]; - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 1) + 12) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 1) + 12) & dev->vram_mask]); p[x + 6] = video_15to32[dat & 0xffff]; p[x + 7] = video_15to32[dat >> 16]; } - dev->ma += (x << 1); - dev->ma &= dev->vram_mask; + dev->memaddr += (x << 1); + dev->memaddr &= dev->vram_mask; } } @@ -3461,7 +3461,7 @@ ibm8514_render_16bpp(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -3469,24 +3469,24 @@ ibm8514_render_16bpp(svga_t *svga) dev->lastline_draw = dev->displine; for (x = 0; x <= dev->h_disp; x += 8) { - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 1)) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 1)) & dev->vram_mask]); p[x] = video_16to32[dat & 0xffff]; p[x + 1] = video_16to32[dat >> 16]; - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 1) + 4) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 1) + 4) & dev->vram_mask]); p[x + 2] = video_16to32[dat & 0xffff]; p[x + 3] = video_16to32[dat >> 16]; - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 1) + 8) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 1) + 8) & dev->vram_mask]); p[x + 4] = video_16to32[dat & 0xffff]; p[x + 5] = video_16to32[dat >> 16]; - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 1) + 12) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 1) + 12) & dev->vram_mask]); p[x + 6] = video_16to32[dat & 0xffff]; p[x + 7] = video_16to32[dat >> 16]; } - dev->ma += (x << 1); - dev->ma &= dev->vram_mask; + dev->memaddr += (x << 1); + dev->memaddr &= dev->vram_mask; } } @@ -3500,7 +3500,7 @@ ibm8514_render_24bpp(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -3508,21 +3508,21 @@ ibm8514_render_24bpp(svga_t *svga) dev->lastline_draw = dev->displine; for (int x = 0; x <= dev->h_disp; x += 4) { - dat = *(uint32_t *) (&dev->vram[dev->ma & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[dev->memaddr & dev->vram_mask]); p[x] = dat & 0xffffff; - dat = *(uint32_t *) (&dev->vram[(dev->ma + 3) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 3) & dev->vram_mask]); p[x + 1] = dat & 0xffffff; - dat = *(uint32_t *) (&dev->vram[(dev->ma + 6) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 6) & dev->vram_mask]); p[x + 2] = dat & 0xffffff; - dat = *(uint32_t *) (&dev->vram[(dev->ma + 9) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 9) & dev->vram_mask]); p[x + 3] = dat & 0xffffff; - dev->ma += 12; + dev->memaddr += 12; } - dev->ma &= dev->vram_mask; + dev->memaddr &= dev->vram_mask; } } @@ -3536,7 +3536,7 @@ ibm8514_render_BGR(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -3544,21 +3544,21 @@ ibm8514_render_BGR(svga_t *svga) dev->lastline_draw = dev->displine; for (int x = 0; x <= dev->h_disp; x += 4) { - dat = *(uint32_t *) (&dev->vram[dev->ma & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[dev->memaddr & dev->vram_mask]); p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); - dat = *(uint32_t *) (&dev->vram[(dev->ma + 3) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 3) & dev->vram_mask]); p[x + 1] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); - dat = *(uint32_t *) (&dev->vram[(dev->ma + 6) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 6) & dev->vram_mask]); p[x + 2] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); - dat = *(uint32_t *) (&dev->vram[(dev->ma + 9) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 9) & dev->vram_mask]); p[x + 3] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); - dev->ma += 12; + dev->memaddr += 12; } - dev->ma &= dev->vram_mask; + dev->memaddr &= dev->vram_mask; } } @@ -3573,7 +3573,7 @@ ibm8514_render_ABGR8888(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -3581,11 +3581,11 @@ ibm8514_render_ABGR8888(svga_t *svga) dev->lastline_draw = dev->displine; for (x = 0; x <= dev->h_disp; x++) { - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 2)) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 2)) & dev->vram_mask]); *p++ = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); } - dev->ma += (x * 4); - dev->ma &= dev->vram_mask; + dev->memaddr += (x * 4); + dev->memaddr &= dev->vram_mask; } } @@ -3600,7 +3600,7 @@ ibm8514_render_32bpp(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || dev->changedvram[(dev->ma >> 12) + 2] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || dev->changedvram[(dev->memaddr >> 12) + 2] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -3608,11 +3608,11 @@ ibm8514_render_32bpp(svga_t *svga) dev->lastline_draw = dev->displine; for (x = 0; x <= dev->h_disp; x++) { - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 2)) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 2)) & dev->vram_mask]); p[x] = dat & 0xffffff; } - dev->ma += (x * 4); - dev->ma &= dev->vram_mask; + dev->memaddr += (x * 4); + dev->memaddr &= dev->vram_mask; } } @@ -3681,7 +3681,7 @@ ibm8514_poll(void *priv) if (dev->dispon) { dev->hdisp_on = 1; - dev->ma &= dev->vram_mask; + dev->memaddr &= dev->vram_mask; if (dev->firstline == 2000) { dev->firstline = dev->displine; @@ -3689,7 +3689,7 @@ ibm8514_poll(void *priv) } if (dev->hwcursor_on) - dev->changedvram[dev->ma >> 12] = dev->changedvram[(dev->ma >> 12) + 1] = dev->interlace ? 3 : 2; + dev->changedvram[dev->memaddr >> 12] = dev->changedvram[(dev->memaddr >> 12) + 1] = dev->interlace ? 3 : 2; svga->render8514(svga); @@ -3726,18 +3726,18 @@ ibm8514_poll(void *priv) dev->linepos = 0; if (dev->dispon) { - if (dev->sc == dev->rowcount) { - dev->sc = 0; - dev->maback += (dev->rowoffset << 3); + if (dev->scanline == dev->rowcount) { + dev->scanline = 0; + dev->memaddr_backup += (dev->rowoffset << 3); if (dev->interlace) - dev->maback += (dev->rowoffset << 3); + dev->memaddr_backup += (dev->rowoffset << 3); - dev->maback &= dev->vram_mask; - dev->ma = dev->maback; + dev->memaddr_backup &= dev->vram_mask; + dev->memaddr = dev->memaddr_backup; } else { - dev->sc++; - dev->sc &= 0x1f; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 0x1f; + dev->memaddr = dev->memaddr_backup; } } @@ -3783,16 +3783,16 @@ ibm8514_poll(void *priv) svga->vslines = 0; if (dev->interlace && dev->oddeven) - dev->ma = dev->maback = (dev->rowoffset << 1); + dev->memaddr = dev->memaddr_backup = (dev->rowoffset << 1); else - dev->ma = dev->maback = 0; + dev->memaddr = dev->memaddr_backup = 0; - dev->ma = (dev->ma << 2); - dev->maback = (dev->maback << 2); + dev->memaddr = (dev->memaddr << 2); + dev->memaddr_backup = (dev->memaddr_backup << 2); } if (dev->vc == dev->v_total) { dev->vc = 0; - dev->sc = (svga->crtc[0x8] & 0x1f); + dev->scanline = (svga->crtc[0x8] & 0x1f); dev->dispon = 1; dev->displine = (dev->interlace && dev->oddeven) ? 1 : 0; diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 9a9be6ff6..9c87746c6 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -109,7 +109,7 @@ ati18800_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -223,7 +223,7 @@ ati18800_recalctimings(svga_t *svga) else { svga->render = svga_render_8bpp_highres; if (!svga->packed_4bpp) { - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; svga->rowoffset <<= 1; } } diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 156e95425..284abe78c 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -206,7 +206,7 @@ ati28800_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -416,10 +416,10 @@ ati28800_recalctimings(svga_t *svga) ((ati28800->regs[0xb9] & 2) << 1); if (ati28800->regs[0xa3] & 0x10) - svga->ma_latch |= 0x10000; + svga->memaddr_latch |= 0x10000; if (ati28800->regs[0xb0] & 0x40) - svga->ma_latch |= 0x20000; + svga->memaddr_latch |= 0x20000; if (ati28800->regs[0xb8] & 0x40) svga->clock *= 2; @@ -483,7 +483,7 @@ ati28800_recalctimings(svga_t *svga) else { svga->render = svga_render_8bpp_highres; if (!svga->packed_4bpp) { - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; svga->rowoffset <<= 1; } } @@ -496,7 +496,7 @@ ati28800_recalctimings(svga_t *svga) svga->hdisp >>= 1; svga->dots_per_clock >>= 1; svga->rowoffset <<= 1; - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; } break; default: diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 026634cf2..74086dab1 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -456,7 +456,7 @@ mach64_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = svga->monitor->mon_changeframecount; svga_recalctimings(svga); @@ -524,14 +524,18 @@ mach64_recalctimings(svga_t *svga) svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; svga->rowoffset = (mach64->crtc_off_pitch >> 22); svga->clock = (cpuclock * (double) (1ULL << 32)) / ics2595_getclock(svga->clock_gen); - svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; + svga->memaddr_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; svga->linedbl = svga->rowcount = 0; svga->split = 0xffffff; svga->vblankstart = svga->dispend; svga->rowcount = mach64->crtc_gen_cntl & 1; svga->rowoffset <<= 1; + if (mach64->type == MACH64_GX) ati68860_ramdac_set_render(svga->ramdac, svga); + + svga->packed_4bpp = !!(((mach64->crtc_gen_cntl >> 8) & 7) == BPP_4); + switch ((mach64->crtc_gen_cntl >> 8) & 7) { case BPP_4: if (mach64->type != MACH64_GX) @@ -572,8 +576,9 @@ mach64_recalctimings(svga_t *svga) } svga->vram_display_mask = mach64->vram_mask; - } else + } else { svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; + } } void @@ -2310,6 +2315,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *priv) { mach64_t *mach64 = (mach64_t *) priv; + svga_t *svga = &mach64->svga; uint8_t ret = 0xff; if (!(addr & 0x400)) { @@ -2524,8 +2530,22 @@ mach64_ext_readb(uint32_t addr, void *priv) case 0xc3: if (mach64->type == MACH64_GX) ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), mach64->svga.ramdac, &mach64->svga); - else - ret = ati68860_ramdac_in(addr & 3, mach64->svga.ramdac, &mach64->svga); + else { + switch (addr & 3) { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + } + } break; case 0xc4: case 0xc5: @@ -2962,7 +2982,7 @@ mach64_ext_readl(uint32_t addr, void *priv) uint32_t ret; if (!(addr & 0x400)) { - mach64_log("nmach64_ext_readl: addr=%04x\n", addr); + mach64_log("mach64_ext_readl: addr=%04x\n", addr); ret = 0xffffffff; } else switch (addr & 0x3ff) { @@ -3101,6 +3121,7 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) } else if (addr & 0x300) { mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE); } else { + mach64_log("mach64_ext_writeb: addr=%04x val=%02x\n", addr & 0x3ff, val); switch (addr & 0x3ff) { case 0x00: case 0x01: @@ -3189,39 +3210,48 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) case 0x62: case 0x63: WRITE8(addr, mach64->cur_clr0, val); - if (mach64->type == MACH64_VT2) - ati68860_ramdac_set_pallook(mach64->svga.ramdac, 0, makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff)); break; case 0x64: case 0x65: case 0x66: case 0x67: WRITE8(addr, mach64->cur_clr1, val); - if (mach64->type == MACH64_VT2) - ati68860_ramdac_set_pallook(mach64->svga.ramdac, 1, makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff)); break; case 0x68: case 0x69: case 0x6a: case 0x6b: WRITE8(addr, mach64->cur_offset, val); - svga->dac_hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8; + if (mach64->type == MACH64_GX) + svga->dac_hwcursor.addr = (mach64->cur_offset & 0xfffff) << 3; + else + svga->hwcursor.addr = (mach64->cur_offset & 0xfffff) << 3; break; case 0x6c: case 0x6d: case 0x6e: case 0x6f: WRITE8(addr, mach64->cur_horz_vert_posn, val); - svga->dac_hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; - svga->dac_hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; + if (mach64->type == MACH64_GX) { + svga->dac_hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; + svga->dac_hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; + } else { + svga->hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; + svga->hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; + } break; case 0x70: case 0x71: case 0x72: case 0x73: WRITE8(addr, mach64->cur_horz_vert_off, val); - svga->dac_hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; - svga->dac_hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; + if (mach64->type == MACH64_GX) { + svga->dac_hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; + svga->dac_hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; + } else { + svga->hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; + svga->hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; + } break; case 0x80: @@ -3283,8 +3313,22 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) case 0xc3: if (mach64->type == MACH64_GX) ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, svga->ramdac, svga); - else - ati68860_ramdac_out(addr & 3, val, svga->ramdac, svga); + else { + switch (addr & 3) { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + } + } break; case 0xc4: case 0xc5: @@ -3294,7 +3338,8 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) mach64_log("Ext RAMDAC TYPE write=%x, bit set=%03x.\n", addr & 0x3ff, mach64->dac_cntl & 0x100); if ((addr & 3) >= 1) { svga_set_ramdac_type(svga, !!(mach64->dac_cntl & 0x100)); - ati68860_set_ramdac_type(svga->ramdac, !!(mach64->dac_cntl & 0x100)); + if (mach64->type == MACH64_GX) + ati68860_set_ramdac_type(svga->ramdac, !!(mach64->dac_cntl & 0x100)); } i2c_gpio_set(mach64->i2c, !(mach64->dac_cntl & 0x20000000) || (mach64->dac_cntl & 0x04000000), !(mach64->dac_cntl & 0x10000000) || (mach64->dac_cntl & 0x02000000)); break; @@ -3306,7 +3351,10 @@ mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv) WRITE8(addr, mach64->gen_test_cntl, val); ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1); mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0); - svga->dac_hwcursor.ena = mach64->gen_test_cntl & 0x80; + if (mach64->type == MACH64_GX) + svga->dac_hwcursor.ena = !!(mach64->gen_test_cntl & 0x80); + else + svga->hwcursor.ena = !!(mach64->gen_test_cntl & 0x80); break; case 0xdc: @@ -3371,6 +3419,7 @@ uint8_t mach64_ext_inb(uint16_t port, void *priv) { mach64_t *mach64 = (mach64_t *) priv; + svga_t *svga = &mach64->svga; uint8_t ret = 0xff; switch (port) { @@ -3384,6 +3433,12 @@ mach64_ext_inb(uint16_t port, void *priv) case 0x7eef: ret = mach64_ext_readb(0x400 | 0x00 | (port & 3), priv); break; + case 0x06ec: + case 0x06ed: + case 0x06ee: + case 0x06ef: + ret = mach64_ext_readb(0x400 | 0x04 | (port & 3), priv); + break; case 0x0aec: case 0x0aed: case 0x0aee: @@ -3519,8 +3574,22 @@ mach64_ext_inb(uint16_t port, void *priv) case 0x5eef: if (mach64->type == MACH64_GX) ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), mach64->svga.ramdac, &mach64->svga); - else - ret = ati68860_ramdac_in(port & 3, mach64->svga.ramdac, &mach64->svga); + else { + switch (port & 3) { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + } + } break; case 0x62ec: @@ -3617,6 +3686,12 @@ mach64_ext_outb(uint16_t port, uint8_t val, void *priv) case 0x7eef: mach64_ext_writeb(0x400 | 0x00 | (port & 3), val, priv); break; + case 0x06ec: + case 0x06ed: + case 0x06ee: + case 0x06ef: + mach64_ext_writeb(0x400 | 0x04 | (port & 3), val, priv); + break; case 0x0aec: case 0x0aed: case 0x0aee: @@ -3745,8 +3820,22 @@ mach64_ext_outb(uint16_t port, uint8_t val, void *priv) case 0x5eef: if (mach64->type == MACH64_GX) ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, svga->ramdac, svga); - else - ati68860_ramdac_out(port & 3, val, svga->ramdac, svga); + else { + switch (port & 3) { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + } + } break; case 0x62ec: @@ -3905,6 +3994,63 @@ mach64_readl(uint32_t addr, void *priv) return ret; } +void +mach64_int_hwcursor_draw(svga_t *svga, int displine) +{ + const mach64_t *mach64 = (mach64_t *) svga->priv; + int comb; + int offset; + int x_pos; + int y_pos; + int shift = 0; + uint16_t dat; + uint32_t col0 = makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff); + uint32_t col1 = makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff); + uint32_t *p; + + offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + if (svga->packed_4bpp) + shift = 1; + + for (int x = 0; x < svga->hwcursor_latch.cur_xsize; x += (8 >> shift)) { + if (shift) { + dat = svga->vram[(svga->hwcursor_latch.addr) & svga->vram_mask] & 0x0f; + dat |= (svga->vram[(svga->hwcursor_latch.addr + 1) & svga->vram_mask] << 4); + dat |= (svga->vram[(svga->hwcursor_latch.addr + 2) & svga->vram_mask] << 8); + dat |= (svga->vram[(svga->hwcursor_latch.addr + 3) & svga->vram_mask] << 12); + } else { + dat = svga->vram[svga->hwcursor_latch.addr & svga->vram_mask]; + dat |= (svga->vram[(svga->hwcursor_latch.addr + 1) & svga->vram_mask] << 8); + } + for (int xx = 0; xx < (8 >> shift); xx++) { + comb = (dat >> (xx << 1)) & 0x03; + + y_pos = displine; + x_pos = offset + svga->x_add; + p = buffer32->line[y_pos]; + + if (offset >= svga->hwcursor_latch.x) { + switch (comb) { + case 0: + p[x_pos] = col0; + break; + case 1: + p[x_pos] = col1; + break; + case 3: + p[x_pos] ^= 0xffffff; + break; + + default: + break; + } + } + offset++; + } + svga->hwcursor_latch.addr += 2; + } +} + #define CLAMP(x) \ do { \ if ((x) & ~0xff) \ @@ -4550,15 +4696,22 @@ mach64_common_init(const device_t *info) svga = &mach64->svga; + mach64->type = info->local & 0xff; mach64->vram_size = device_get_config_int("memory"); mach64->vram_mask = (mach64->vram_size << 20) - 1; - svga_init(info, svga, mach64, mach64->vram_size << 20, - mach64_recalctimings, - mach64_in, mach64_out, - NULL, - mach64_overlay_draw); - svga->dac_hwcursor.cur_ysize = 64; + if (mach64->type > MACH64_GX) + svga_init(info, svga, mach64, mach64->vram_size << 20, + mach64_recalctimings, + mach64_in, mach64_out, + mach64_int_hwcursor_draw, + mach64_overlay_draw); + else + svga_init(info, svga, mach64, mach64->vram_size << 20, + mach64_recalctimings, + mach64_in, mach64_out, + NULL, + mach64_overlay_draw); mem_mapping_add(&mach64->linear_mapping, 0, 0, mach64_read_linear, mach64_readw_linear, mach64_readl_linear, mach64_write_linear, mach64_writew_linear, mach64_writel_linear, NULL, MEM_MAPPING_EXTERNAL, svga); mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, MEM_MAPPING_EXTERNAL, mach64); @@ -4576,9 +4729,6 @@ mach64_common_init(const device_t *info) mach64->pci_regs[0x32] = 0x0c; mach64->pci_regs[0x33] = 0x00; - svga->ramdac = device_add(&ati68860_ramdac_device); - svga->dac_hwcursor_draw = ati68860_hwcursor_draw; - svga->clock_gen = device_add(&ics2595_device); mach64->dst_cntl = 3; @@ -4598,6 +4748,13 @@ static void * mach64gx_init(const device_t *info) { mach64_t *mach64 = mach64_common_init(info); + svga_t *svga = &mach64->svga; + + svga->ramdac = device_add(&ati68860_ramdac_device); + svga->dac_hwcursor_draw = ati68860_hwcursor_draw; + + svga->dac_hwcursor.cur_ysize = 64; + svga->dac_hwcursor.cur_xsize = 64; if (info->flags & DEVICE_ISA16) video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_isa); @@ -4606,12 +4763,11 @@ mach64gx_init(const device_t *info) else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_vlb); - mach64->type = MACH64_GX; mach64->pci = !!(info->flags & DEVICE_PCI); mach64->pci_id = 'X' | ('G' << 8); mach64->config_chip_id = 0x000000d7; mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ - mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI-68860, 256Kx16 DRAM*/ + mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI 68860, 256Kx16 DRAM*/ if (info->flags & DEVICE_PCI) { mach64->config_stat0 |= 7; /*PCI, 256Kx16 DRAM*/ ati_eeprom_load(&mach64->eeprom, "mach64_pci.nvr", 1); @@ -4635,9 +4791,13 @@ mach64vt2_init(const device_t *info) mach64_t *mach64 = mach64_common_init(info); svga_t *svga = &mach64->svga; + svga->dac_hwcursor_draw = NULL; + + svga->hwcursor.cur_ysize = 64; + svga->hwcursor.cur_xsize = 64; + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_mach64_pci); - mach64->type = MACH64_VT2; mach64->pci = 1; mach64->pci_id = 0x5654; mach64->config_chip_id = 0x40005654; @@ -4757,7 +4917,7 @@ const device_t mach64gx_isa_device = { .name = "ATI Mach64GX ISA", .internal_name = "mach64gx_isa", .flags = DEVICE_ISA16, - .local = 0, + .local = MACH64_GX, .init = mach64gx_init, .close = mach64_close, .reset = NULL, @@ -4771,7 +4931,7 @@ const device_t mach64gx_vlb_device = { .name = "ATI Mach64GX VLB", .internal_name = "mach64gx_vlb", .flags = DEVICE_VLB, - .local = 0, + .local = MACH64_GX, .init = mach64gx_init, .close = mach64_close, .reset = NULL, @@ -4785,7 +4945,7 @@ const device_t mach64gx_pci_device = { .name = "ATI Mach64GX PCI", .internal_name = "mach64gx_pci", .flags = DEVICE_PCI, - .local = 0, + .local = MACH64_GX, .init = mach64gx_init, .close = mach64_close, .reset = NULL, @@ -4799,7 +4959,7 @@ const device_t mach64vt2_device = { .name = "ATI Mach64VT2", .internal_name = "mach64vt2", .flags = DEVICE_PCI, - .local = 0, + .local = MACH64_VT2, .init = mach64vt2_init, .close = mach64_close, .reset = NULL, diff --git a/src/video/vid_ati_mach8.c b/src/video/vid_ati_mach8.c index f7b5e0915..4133b730e 100644 --- a/src/video/vid_ati_mach8.c +++ b/src/video/vid_ati_mach8.c @@ -817,6 +817,10 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 dev->accel.dy |= ~0x5ff; /*Destination Width*/ + mach->accel.dx_first_row_start = dev->accel.cur_x; + if (dev->accel.cur_x >= 0x600) + mach->accel.dx_first_row_start |= ~0x5ff; + mach->accel.dx_start = mach->accel.dest_x_start; if (mach->accel.dest_x_start >= 0x600) mach->accel.dx_start |= ~0x5ff; @@ -831,16 +835,9 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 } else if (mach->accel.dx_end < mach->accel.dx_start) { mach->accel.width = (mach->accel.dx_start - mach->accel.dx_end); mach->accel.stepx = -1; - if (dev->accel.dx > 0) - dev->accel.dx--; - mach_log("BitBLT: Dst Negative X, dxstart = %d, end = %d, width = %d, dx = %d, dpconfig = %04x.\n", - mach->accel.dest_x_start, mach->accel.dest_x_end, mach->accel.width, dev->accel.dx, - mach->accel.dp_config); } else { mach->accel.stepx = 1; mach->accel.width = 0; - mach_log("BitBLT: Dst Indeterminate X, dpconfig = %04x, destxend = %d, destxstart = %d.\n", - mach->accel.dp_config, mach->accel.dest_x_end, mach->accel.dest_x_start); } dev->accel.sx = 0; @@ -869,6 +866,24 @@ mach_accel_start(int cmd_type, int cpu_input, int count, uint32_t mix_dat, uint3 if (mach->accel.dp_config == 0x4011) mach->accel.height++; + if (mach->accel.height == 1) { + if (mach->accel.dx_end > mach->accel.dx_first_row_start) { + mach->accel.width = (mach->accel.dx_end - mach->accel.dx_first_row_start); + mach->accel.stepx = 1; + } else if (mach->accel.dx_end < mach->accel.dx_first_row_start) { + mach->accel.width = (mach->accel.dx_first_row_start - mach->accel.dx_end); + mach->accel.stepx = -1; + } else { + mach->accel.stepx = 1; + mach->accel.width = 0; + } + } + + if (mach->accel.stepx == -1) { + if (dev->accel.dx > 0) + dev->accel.dx--; + } + dev->accel.sy = 0; dev->accel.dest = mach->accel.dst_ge_offset + (dev->accel.dy * mach->accel.dst_pitch); @@ -2461,7 +2476,7 @@ mach_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = svga->monitor->mon_changeframecount; svga_recalctimings(svga); @@ -2604,7 +2619,7 @@ ati_render_24bpp(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -2613,38 +2628,38 @@ ati_render_24bpp(svga_t *svga) if (mach->accel.ext_ge_config & 0x400) { /*BGR, Blue-(23:16), Green-(15:8), Red-(7:0)*/ for (int x = 0; x <= dev->h_disp; x += 4) { - dat = *(uint32_t *) (&dev->vram[dev->ma & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[dev->memaddr & dev->vram_mask]); p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); - dat = *(uint32_t *) (&dev->vram[(dev->ma + 3) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 3) & dev->vram_mask]); p[x + 1] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); - dat = *(uint32_t *) (&dev->vram[(dev->ma + 6) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 6) & dev->vram_mask]); p[x + 2] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); - dat = *(uint32_t *) (&dev->vram[(dev->ma + 9) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 9) & dev->vram_mask]); p[x + 3] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); - dev->ma += 12; + dev->memaddr += 12; } } else { /*RGB, Red-(23:16), Green-(15:8), Blue-(7:0)*/ for (int x = 0; x <= dev->h_disp; x += 4) { - dat = *(uint32_t *) (&dev->vram[dev->ma & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[dev->memaddr & dev->vram_mask]); p[x] = dat & 0xffffff; - dat = *(uint32_t *) (&dev->vram[(dev->ma + 3) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 3) & dev->vram_mask]); p[x + 1] = dat & 0xffffff; - dat = *(uint32_t *) (&dev->vram[(dev->ma + 6) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 6) & dev->vram_mask]); p[x + 2] = dat & 0xffffff; - dat = *(uint32_t *) (&dev->vram[(dev->ma + 9) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + 9) & dev->vram_mask]); p[x + 3] = dat & 0xffffff; - dev->ma += 12; + dev->memaddr += 12; } } - dev->ma &= dev->vram_mask; + dev->memaddr &= dev->vram_mask; } } @@ -2660,7 +2675,7 @@ ati_render_32bpp(svga_t *svga) if ((dev->displine + svga->y_add) < 0) return; - if (dev->changedvram[dev->ma >> 12] || dev->changedvram[(dev->ma >> 12) + 1] || dev->changedvram[(dev->ma >> 12) + 2] || svga->fullchange) { + if (dev->changedvram[dev->memaddr >> 12] || dev->changedvram[(dev->memaddr >> 12) + 1] || dev->changedvram[(dev->memaddr >> 12) + 2] || svga->fullchange) { p = &buffer32->line[dev->displine + svga->y_add][svga->x_add]; if (dev->firstline_draw == 2000) @@ -2669,17 +2684,17 @@ ati_render_32bpp(svga_t *svga) if (mach->accel.ext_ge_config & 0x400) { /*BGR, Blue-(23:16), Green-(15:8), Red-(7:0)*/ for (x = 0; x <= dev->h_disp; x++) { - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 2)) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 2)) & dev->vram_mask]); *p++ = ((dat & 0x00ff0000) >> 16) | (dat & 0x0000ff00) | ((dat & 0x000000ff) << 16); } } else { /*RGB, Red-(31:24), Green-(23:16), Blue-(15:8)*/ for (x = 0; x <= dev->h_disp; x++) { - dat = *(uint32_t *) (&dev->vram[(dev->ma + (x << 2)) & dev->vram_mask]); + dat = *(uint32_t *) (&dev->vram[(dev->memaddr + (x << 2)) & dev->vram_mask]); *p++ = ((dat & 0xffffff00) >> 8); } } - dev->ma += (x * 4); - dev->ma &= dev->vram_mask; + dev->memaddr += (x * 4); + dev->memaddr &= dev->vram_mask; } } @@ -2847,17 +2862,17 @@ mach_recalctimings(svga_t *svga) if (ATI_MACH32) { if (mach->regs[0xad] & 0x04) - svga->ma_latch |= 0x40000; + svga->memaddr_latch |= 0x40000; if (mach->regs[0xad] & 0x08) - svga->ma_latch |= 0x80000; + svga->memaddr_latch |= 0x80000; } if (mach->regs[0xa3] & 0x10) - svga->ma_latch |= 0x10000; + svga->memaddr_latch |= 0x10000; if (mach->regs[0xb0] & 0x40) - svga->ma_latch |= 0x20000; + svga->memaddr_latch |= 0x20000; if ((mach->regs[0xb6] & 0x18) >= 0x10) { svga->hdisp <<= 1; @@ -2886,7 +2901,7 @@ mach_recalctimings(svga_t *svga) mach_log("ON=%d, override=%d, gelo=%04x, gehi=%04x, vgahdisp=%d.\n", dev->on, svga->override, mach->accel.ge_offset_lo, mach->accel.ge_offset_hi, svga->hdisp); if (dev->on) { - dev->ma_latch = 0; /*(mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;*/ + dev->memaddr_latch = 0; /*(mach->accel.crt_offset_lo | (mach->accel.crt_offset_hi << 16)) << 2;*/ dev->interlace = !!(dev->disp_cntl & 0x10); dev->pitch = dev->ext_pitch; dev->rowoffset = dev->ext_crt_pitch; @@ -3085,7 +3100,7 @@ mach_recalctimings(svga_t *svga) else { svga->render = svga_render_8bpp_highres; if (!svga->packed_4bpp) { - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; svga->rowoffset <<= 1; } } @@ -3297,7 +3312,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u case 0x42e8: case 0x42e9: - mach_log("VBLANK stat=%02x, val=%02x.\n", dev->subsys_stat, val); + mach_log("VBLANK status=%02x, val=%02x.\n", dev->subsys_stat, val); if (len == 2) dev->subsys_cntl = val; else { @@ -3972,7 +3987,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; case 0x92ee: - mach_log("Write port 92ee, malatch=%08x.\n", svga->ma_latch); + mach_log("Write port 92ee, malatch=%08x.\n", svga->memaddr_latch); break; case 0x96ee: @@ -4227,7 +4242,7 @@ mach_accel_out_fifo(mach_t *mach, svga_t *svga, ibm8514_t *dev, uint16_t port, u break; default: - mach_log("Unknown or reserved write to %04x, val=%04x, len=%d, latch=%08x.\n", port, val, len, svga->ma_latch); + mach_log("Unknown or reserved write to %04x, val=%04x, len=%d, latch=%08x.\n", port, val, len, svga->memaddr_latch); break; } } @@ -6475,6 +6490,7 @@ ati8514_io_set(svga_t *svga) io_sethandler(0xeeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xf2ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xf6ee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); + io_sethandler(0xfaee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); io_sethandler(0xfeee, 0x0002, ati8514_accel_inb, ati8514_accel_inw, ati8514_accel_inl, ati8514_accel_outb, ati8514_accel_outw, ati8514_accel_outl, svga); } diff --git a/src/video/vid_bochs_vbe.c b/src/video/vid_bochs_vbe.c index a87890c75..fd5772b19 100644 --- a/src/video/vid_bochs_vbe.c +++ b/src/video/vid_bochs_vbe.c @@ -336,13 +336,13 @@ bochs_vbe_recalctimings(svga_t* svga) if (svga->bpp == 4) { svga->rowoffset = (dev->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] / 2) >> 3; - svga->ma_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + + svga->memaddr_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] >> 3); svga->fullchange = 3; } else { svga->rowoffset = dev->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8)); - svga->ma_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + + svga->memaddr_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8))); svga->fullchange = 3; } @@ -470,11 +470,11 @@ bochs_vbe_outw(const uint16_t addr, const uint16_t val, void *priv) svga_t *svga = &dev->svga; if (svga->bpp == 4) { svga->rowoffset = (dev->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] / 2) >> 3; - svga->ma_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + + svga->memaddr_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] >> 3); } else { svga->rowoffset = dev->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8)); - svga->ma_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + + svga->memaddr_latch = (dev->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] * svga->rowoffset) + (dev->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] * ((svga->bpp == 15) ? 2 : (svga->bpp / 8))); } @@ -575,7 +575,7 @@ bochs_vbe_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 4a9a032c5..79b9360f5 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -16,7 +16,7 @@ * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. - * Copyright 2023 W. M. Martine + * Copyright 2023 W. M. Martinez */ #include #include @@ -75,7 +75,7 @@ cga_update_latch(cga_t *cga) { uint32_t lp_latch = cga->displine * cga->crtc[CGA_CRTC_HDISP]; - cga->crtc[0x10] = (lp_latch >> 8) & 0x3f; + cga->crtc[CGA_CRTC_LIGHT_PEN_ADDR_HIGH] = (lp_latch >> 8) & 0x3f; cga->crtc[CGA_CRTC_LIGHT_PEN_ADDR_LOW] = lp_latch & 0xff; } @@ -253,10 +253,10 @@ cga_recalctimings(cga_t *cga) static void cga_render(cga_t *cga, int line) { - uint16_t ca = (cga->crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (cga->crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; + uint16_t cursoraddr = (cga->crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (cga->crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; int drawcursor; int x; - int c; + int column; uint8_t chr; uint8_t attr; uint16_t dat; @@ -266,20 +266,20 @@ cga_render(cga_t *cga, int line) int32_t highres_graphics_flag = (CGA_MODE_FLAG_HIGHRES_GRAPHICS | CGA_MODE_FLAG_GRAPHICS); if (((cga->cgamode & highres_graphics_flag) == highres_graphics_flag)) { - for (c = 0; c < 8; ++c) { - buffer32->line[line][c] = 0; + for (column = 0; column < 8; ++column) { + buffer32->line[line][column] = 0; if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) - buffer32->line[line][c + (cga->crtc[CGA_CRTC_HDISP] << 3) + 8] = 0; + buffer32->line[line][column + (cga->crtc[CGA_CRTC_HDISP] << 3) + 8] = 0; else - buffer32->line[line][c + (cga->crtc[CGA_CRTC_HDISP] << 4) + 8] = 0; + buffer32->line[line][column + (cga->crtc[CGA_CRTC_HDISP] << 4) + 8] = 0; } } else { - for (c = 0; c < 8; ++c) { - buffer32->line[line][c] = (cga->cgacol & 15) + 16; + for (column = 0; column < 8; ++column) { + buffer32->line[line][column] = (cga->cgacol & 15) + 16; if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) - buffer32->line[line][c + (cga->crtc[CGA_CRTC_HDISP] << 3) + 8] = (cga->cgacol & 15) + 16; + buffer32->line[line][column + (cga->crtc[CGA_CRTC_HDISP] << 3) + 8] = (cga->cgacol & 15) + 16; else - buffer32->line[line][c + (cga->crtc[CGA_CRTC_HDISP] << 4) + 8] = (cga->cgacol & 15) + 16; + buffer32->line[line][column + (cga->crtc[CGA_CRTC_HDISP] << 4) + 8] = (cga->cgacol & 15) + 16; } } if (cga->cgamode & CGA_MODE_FLAG_HIGHRES) { @@ -289,7 +289,7 @@ cga_render(cga_t *cga, int line) attr = cga->charbuffer[(x << 1) + 1]; } else chr = attr = 0; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + drawcursor = ((cga->memaddr == cursoraddr) && cga->cursorvisible && cga->cursoron); cols[1] = (attr & 15) + 16; if (cga->cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; @@ -298,26 +298,26 @@ cga_render(cga_t *cga, int line) } else cols[0] = (attr >> 4) + 16; if (drawcursor) { - for (c = 0; c < 8; c++) { - buffer32->line[line][(x << 3) + c + 8] - = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + for (column = 0; column < 8; column++) { + buffer32->line[line][(x << 3) + column + 8] + = cols[(fontdat[chr + cga->fontbase][cga->scanline & 7] & (1 << (column ^ 7))) ? 1 : 0] ^ 15; } } else { - for (c = 0; c < 8; c++) { - buffer32->line[line][(x << 3) + c + 8] - = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + for (column = 0; column < 8; column++) { + buffer32->line[line][(x << 3) + column + 8] + = cols[(fontdat[chr + cga->fontbase][cga->scanline & 7] & (1 << (column ^ 7))) ? 1 : 0]; } } - cga->ma++; + cga->memaddr++; } - } else if (!(cga->cgamode & 2)) { + } else if (!(cga->cgamode & CGA_MODE_FLAG_GRAPHICS)) { for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { if (cga->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { - chr = cga->vram[(cga->ma << 1) & 0x3fff]; - attr = cga->vram[((cga->ma << 1) + 1) & 0x3fff]; + chr = cga->vram[(cga->memaddr << 1) & 0x3fff]; + attr = cga->vram[((cga->memaddr << 1) + 1) & 0x3fff]; } else chr = attr = 0; - drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + drawcursor = ((cga->memaddr == cursoraddr) && cga->cursorvisible && cga->cursoron); cols[1] = (attr & 15) + 16; if (cga->cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; @@ -325,18 +325,18 @@ cga_render(cga_t *cga, int line) cols[1] = cols[0]; } else cols[0] = (attr >> 4) + 16; - cga->ma++; + cga->memaddr++; if (drawcursor) { - for (c = 0; c < 8; c++) { - buffer32->line[line][(x << 4) + (c << 1) + 8] - = buffer32->line[line][(x << 4) + (c << 1) + 9] - = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + for (column = 0; column < 8; column++) { + buffer32->line[line][(x << 4) + (column << 1) + 8] + = buffer32->line[line][(x << 4) + (column << 1) + 9] + = cols[(fontdat[chr + cga->fontbase][cga->scanline & 7] & (1 << (column ^ 7))) ? 1 : 0] ^ 15; } } else { - for (c = 0; c < 8; c++) { - buffer32->line[line][(x << 4) + (c << 1) + 8] - = buffer32->line[line][(x << 4) + (c << 1) + 9] - = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + for (column = 0; column < 8; column++) { + buffer32->line[line][(x << 4) + (column << 1) + 8] + = buffer32->line[line][(x << 4) + (column << 1) + 9] + = cols[(fontdat[chr + cga->fontbase][cga->scanline & 7] & (1 << (column ^ 7))) ? 1 : 0]; } } } @@ -358,14 +358,14 @@ cga_render(cga_t *cga, int line) } for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { if (cga->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) - dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | - cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + dat = (cga->vram[((cga->memaddr << 1) & 0x1fff) + ((cga->scanline & 1) * 0x2000)] << 8) | + cga->vram[((cga->memaddr << 1) & 0x1fff) + ((cga->scanline & 1) * 0x2000) + 1]; else dat = 0; - cga->ma++; - for (c = 0; c < 8; c++) { - buffer32->line[line][(x << 4) + (c << 1) + 8] - = buffer32->line[line][(x << 4) + (c << 1) + 9] + cga->memaddr++; + for (column = 0; column < 8; column++) { + buffer32->line[line][(x << 4) + (column << 1) + 8] + = buffer32->line[line][(x << 4) + (column << 1) + 9] = cols[dat >> 14]; dat <<= 2; } @@ -375,13 +375,13 @@ cga_render(cga_t *cga, int line) cols[1] = (cga->cgacol & 15) + 16; for (x = 0; x < cga->crtc[CGA_CRTC_HDISP]; x++) { if (cga->cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) - dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | - cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + dat = (cga->vram[((cga->memaddr << 1) & 0x1fff) + ((cga->scanline & 1) * 0x2000)] << 8) | + cga->vram[((cga->memaddr << 1) & 0x1fff) + ((cga->scanline & 1) * 0x2000) + 1]; else dat = 0; - cga->ma++; - for (c = 0; c < 16; c++) { - buffer32->line[line][(x << 4) + c + 8] = cols[dat >> 15]; + cga->memaddr++; + for (column = 0; column < 16; column++) { + buffer32->line[line][(x << 4) + column + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -519,7 +519,7 @@ cga_poll(void *priv) { cga_t *cga = (cga_t *) priv; int x; - int oldsc; + int scanline_old; int oldvc; int xs_temp; int ys_temp; @@ -529,9 +529,9 @@ cga_poll(void *priv) timer_advance_u64(&cga->timer, cga->dispofftime); cga->cgastat |= 1; cga->linepos = 1; - oldsc = cga->sc; + scanline_old = cga->scanline; if ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3) - cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; + cga->scanline = ((cga->scanline << 1) + cga->oddeven) & 7; if (cga->cgadispon) { if (cga->displine < cga->firstline) { cga->firstline = cga->displine; @@ -547,9 +547,9 @@ cga_poll(void *priv) cga_render(cga, cga->displine); break; case DOUBLE_SIMPLE: - old_ma = cga->ma; + old_ma = cga->memaddr; cga_render(cga, cga->displine << 1); - cga->ma = old_ma; + cga->memaddr = old_ma; cga_render(cga, (cga->displine << 1) + 1); break; } @@ -578,8 +578,8 @@ cga_poll(void *priv) break; } - cga->sc = oldsc; - if (cga->vc == cga->crtc[CGA_CRTC_VSYNC] && !cga->sc) + cga->scanline = scanline_old; + if (cga->vc == cga->crtc[CGA_CRTC_VSYNC] && !cga->scanline) cga->cgastat |= 8; cga->displine++; if (cga->displine >= 360) @@ -592,25 +592,25 @@ cga_poll(void *priv) if (!cga->vsynctime) cga->cgastat &= ~8; } - if (cga->sc == (cga->crtc[CGA_CRTC_CURSOR_END] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && - cga->sc == ((cga->crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { - cga->con = 0; + if (cga->scanline == (cga->crtc[CGA_CRTC_CURSOR_END] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && + cga->scanline == ((cga->crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + cga->cursorvisible = 0; } - if ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->sc == (cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) - cga->maback = cga->ma; + if ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && cga->scanline == (cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) + cga->memaddr_backup = cga->memaddr; if (cga->vadj) { - cga->sc++; - cga->sc &= 31; - cga->ma = cga->maback; + cga->scanline++; + cga->scanline &= 31; + cga->memaddr = cga->memaddr_backup; cga->vadj--; if (!cga->vadj) { cga->cgadispon = 1; - cga->ma = cga->maback = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; - cga->sc = 0; + cga->memaddr = cga->memaddr_backup = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + cga->scanline = 0; } - } else if (cga->sc == cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR]) { - cga->maback = cga->ma; - cga->sc = 0; + } else if (cga->scanline == cga->crtc[CGA_CRTC_MAX_SCANLINE_ADDR]) { + cga->memaddr_backup = cga->memaddr; + cga->scanline = 0; oldvc = cga->vc; cga->vc++; cga->vc &= 127; @@ -623,8 +623,9 @@ cga_poll(void *priv) cga->vadj = cga->crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!cga->vadj) { cga->cgadispon = 1; - cga->ma = cga->maback = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + cga->memaddr = cga->memaddr_backup = (cga->crtc[CGA_CRTC_START_ADDR_LOW] | (cga->crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; } + switch (cga->crtc[CGA_CRTC_CURSOR_START] & 0x60) { case 0x20: cga->cursoron = 0; @@ -716,18 +717,18 @@ cga_poll(void *priv) cga->oddeven ^= 1; } } else { - cga->sc++; - cga->sc &= 31; - cga->ma = cga->maback; + cga->scanline++; + cga->scanline &= 31; + cga->memaddr = cga->memaddr_backup; } if (cga->cgadispon) cga->cgastat &= ~1; - if (cga->sc == (cga->crtc[CGA_CRTC_CURSOR_START] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && - cga->sc == ((cga->crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) - cga->con = 1; + if (cga->scanline == (cga->crtc[CGA_CRTC_CURSOR_START] & 31) || ((cga->crtc[CGA_CRTC_INTERLACE] & 3) == 3 && + cga->scanline == ((cga->crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + cga->cursorvisible = 1; if (cga->cgadispon && (cga->cgamode & CGA_MODE_FLAG_HIGHRES)) { for (x = 0; x < (cga->crtc[CGA_CRTC_HDISP] << 1); x++) - cga->charbuffer[x] = cga->vram[((cga->ma << 1) + x) & 0x3fff]; + cga->charbuffer[x] = cga->vram[((cga->memaddr << 1) + x) & 0x3fff]; } } } @@ -776,6 +777,18 @@ cga_standalone_init(UNUSED(const device_t *info)) } } + switch(device_get_config_int("font")) { + case 0: + loadfont(FONT_IBM_MDA_437_PATH, 0); + break; + case 1: + loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + break; + case 4: + loadfont(FONT_TULIP_DGA_PATH, 0); + break; + } + return cga; } @@ -879,6 +892,22 @@ const device_config_t cga_config[] = { }, .bios = { { 0 } } }, + { + .name = "font", + .description = "Font", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "US (CP 437)", .value = 0 }, + { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, + { .description = "Tulip DGA", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "snow_enabled", .description = "Snow emulation", diff --git a/src/video/vid_colorplus.c b/src/video/vid_cga_colorplus.c similarity index 70% rename from src/video/vid_colorplus.c rename to src/video/vid_cga_colorplus.c index 7daba018e..af8fd6d99 100644 --- a/src/video/vid_colorplus.c +++ b/src/video/vid_cga_colorplus.c @@ -37,16 +37,19 @@ #include <86box/plat_unused.h> /* Bits in the colorplus control register: */ -#define COLORPLUS_PLANE_SWAP 0x40 /* Swap planes at 0000h and 4000h */ -#define COLORPLUS_640x200_MODE 0x20 /* 640x200x4 mode active */ -#define COLORPLUS_320x200_MODE 0x10 /* 320x200x16 mode active */ -#define COLORPLUS_EITHER_MODE 0x30 /* Either mode active */ +#define COLORPLUS_PLANE_SWAP 0x40 /* Swap planes at 0000h and 4000h */ +#define COLORPLUS_640x200_MODE 0x20 /* 640x200x4 mode active */ +#define COLORPLUS_320x200_MODE 0x10 /* 320x200x16 mode active */ +#define COLORPLUS_EITHER_MODE 0x30 /* Either mode active */ -#define CGA_RGB 0 -#define CGA_COMPOSITE 1 +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 -#define COMPOSITE_OLD 0 -#define COMPOSITE_NEW 1 +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + +// Plantronics specific registers +#define COLORPLUS_CONTROL 0x3DD video_timings_t timing_colorplus = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; @@ -57,7 +60,7 @@ colorplus_out(uint16_t addr, uint8_t val, void *priv) { colorplus_t *colorplus = (colorplus_t *) priv; - if (addr == 0x3DD) { + if (addr == COLORPLUS_CONTROL) { colorplus->control = val & 0x70; } else { cga_out(addr, val, &colorplus->cga); @@ -127,7 +130,7 @@ colorplus_poll(void *priv) uint16_t dat1; int cols[4]; int col; - int oldsc; + int scanline_old; static const int cols16[16] = { 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x11, 0x13, 0x15, 0x17, @@ -146,9 +149,9 @@ colorplus_poll(void *priv) timer_advance_u64(&colorplus->cga.timer, colorplus->cga.dispofftime); colorplus->cga.cgastat |= 1; colorplus->cga.linepos = 1; - oldsc = colorplus->cga.sc; - if ((colorplus->cga.crtc[8] & 3) == 3) - colorplus->cga.sc = ((colorplus->cga.sc << 1) + colorplus->cga.oddeven) & 7; + scanline_old = colorplus->cga.scanline; + if ((colorplus->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3) + colorplus->cga.scanline = ((colorplus->cga.scanline << 1) + colorplus->cga.oddeven) & 7; if (colorplus->cga.cgadispon) { if (colorplus->cga.displine < colorplus->cga.firstline) { colorplus->cga.firstline = colorplus->cga.displine; @@ -157,13 +160,13 @@ colorplus_poll(void *priv) colorplus->cga.lastline = colorplus->cga.displine; /* Left / right border */ for (c = 0; c < 8; c++) { - buffer32->line[colorplus->cga.displine][c] = buffer32->line[colorplus->cga.displine][c + (colorplus->cga.crtc[1] << 4) + 8] = (colorplus->cga.cgacol & 15) + 16; + buffer32->line[colorplus->cga.displine][c] = buffer32->line[colorplus->cga.displine][c + (colorplus->cga.crtc[CGA_CRTC_HDISP] << 4) + 8] = (colorplus->cga.cgacol & 15) + 16; } if (colorplus->control & COLORPLUS_320x200_MODE) { - for (x = 0; x < colorplus->cga.crtc[1]; x++) { - dat0 = (plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; - dat1 = (plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; - colorplus->cga.ma++; + for (x = 0; x < colorplus->cga.crtc[CGA_CRTC_HDISP]; x++) { + dat0 = (plane0[((colorplus->cga.memaddr << 1) & 0x1fff) + ((colorplus->cga.scanline & 1) * 0x2000)] << 8) | plane0[((colorplus->cga.memaddr << 1) & 0x1fff) + ((colorplus->cga.scanline & 1) * 0x2000) + 1]; + dat1 = (plane1[((colorplus->cga.memaddr << 1) & 0x1fff) + ((colorplus->cga.scanline & 1) * 0x2000)] << 8) | plane1[((colorplus->cga.memaddr << 1) & 0x1fff) + ((colorplus->cga.scanline & 1) * 0x2000) + 1]; + colorplus->cga.memaddr++; for (c = 0; c < 8; c++) { buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]; dat0 <<= 2; @@ -173,7 +176,7 @@ colorplus_poll(void *priv) } else if (colorplus->control & COLORPLUS_640x200_MODE) { cols[0] = (colorplus->cga.cgacol & 15) | 16; col = (colorplus->cga.cgacol & 16) ? 24 : 16; - if (colorplus->cga.cgamode & 4) { + if (colorplus->cga.cgamode & CGA_MODE_FLAG_BW) { cols[1] = col | 3; cols[2] = col | 4; cols[3] = col | 7; @@ -186,10 +189,10 @@ colorplus_poll(void *priv) cols[2] = col | 4; cols[3] = col | 6; } - for (x = 0; x < colorplus->cga.crtc[1]; x++) { - dat0 = (plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; - dat1 = (plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; - colorplus->cga.ma++; + for (x = 0; x < colorplus->cga.crtc[CGA_CRTC_HDISP]; x++) { + dat0 = (plane0[((colorplus->cga.memaddr << 1) & 0x1fff) + ((colorplus->cga.scanline & 1) * 0x2000)] << 8) | plane0[((colorplus->cga.memaddr << 1) & 0x1fff) + ((colorplus->cga.scanline & 1) * 0x2000) + 1]; + dat1 = (plane1[((colorplus->cga.memaddr << 1) & 0x1fff) + ((colorplus->cga.scanline & 1) * 0x2000)] << 8) | plane1[((colorplus->cga.memaddr << 1) & 0x1fff) + ((colorplus->cga.scanline & 1) * 0x2000) + 1]; + colorplus->cga.memaddr++; for (c = 0; c < 16; c++) { buffer32->line[colorplus->cga.displine][(x << 4) + c + 8] = cols[(dat0 >> 15) | ((dat1 >> 15) << 1)]; dat0 <<= 1; @@ -200,18 +203,18 @@ colorplus_poll(void *priv) } else /* Top / bottom border */ { cols[0] = (colorplus->cga.cgacol & 15) + 16; - hline(buffer32, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, colorplus->cga.displine, (colorplus->cga.crtc[CGA_CRTC_HDISP] << 4) + 16, cols[0]); } - x = (colorplus->cga.crtc[1] << 4) + 16; + x = (colorplus->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; if (colorplus->cga.composite) Composite_Process(colorplus->cga.cgamode, 0, x >> 2, buffer32->line[colorplus->cga.displine]); else video_process_8(x, colorplus->cga.displine); - colorplus->cga.sc = oldsc; - if (colorplus->cga.vc == colorplus->cga.crtc[7] && !colorplus->cga.sc) + colorplus->cga.scanline = scanline_old; + if (colorplus->cga.vc == colorplus->cga.crtc[CGA_CRTC_VSYNC] && !colorplus->cga.scanline) colorplus->cga.cgastat |= 8; colorplus->cga.displine++; if (colorplus->cga.displine >= 360) @@ -224,53 +227,54 @@ colorplus_poll(void *priv) if (!colorplus->cga.vsynctime) colorplus->cga.cgastat &= ~8; } - if (colorplus->cga.sc == (colorplus->cga.crtc[11] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[11] & 31) >> 1))) { - colorplus->cga.con = 0; + if (colorplus->cga.scanline == (colorplus->cga.crtc[CGA_CRTC_CURSOR_END] & 31) + || ((colorplus->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && colorplus->cga.scanline == ((colorplus->cga.crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + colorplus->cga.cursorvisible = 0; } - if ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == (colorplus->cga.crtc[9] >> 1)) - colorplus->cga.maback = colorplus->cga.ma; + if ((colorplus->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && colorplus->cga.scanline == (colorplus->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) + colorplus->cga.memaddr_backup = colorplus->cga.memaddr; if (colorplus->cga.vadj) { - colorplus->cga.sc++; - colorplus->cga.sc &= 31; - colorplus->cga.ma = colorplus->cga.maback; + colorplus->cga.scanline++; + colorplus->cga.scanline &= 31; + colorplus->cga.memaddr = colorplus->cga.memaddr_backup; colorplus->cga.vadj--; if (!colorplus->cga.vadj) { colorplus->cga.cgadispon = 1; - colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[13] | (colorplus->cga.crtc[12] << 8)) & 0x3fff; - colorplus->cga.sc = 0; + colorplus->cga.memaddr = colorplus->cga.memaddr_backup = (colorplus->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (colorplus->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + colorplus->cga.scanline = 0; } - } else if (colorplus->cga.sc == colorplus->cga.crtc[9]) { - colorplus->cga.maback = colorplus->cga.ma; - colorplus->cga.sc = 0; + } else if (colorplus->cga.scanline == colorplus->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR]) { + colorplus->cga.memaddr_backup = colorplus->cga.memaddr; + colorplus->cga.scanline = 0; oldvc = colorplus->cga.vc; colorplus->cga.vc++; colorplus->cga.vc &= 127; - if (colorplus->cga.vc == colorplus->cga.crtc[6]) + if (colorplus->cga.vc == colorplus->cga.crtc[CGA_CRTC_VDISP]) colorplus->cga.cgadispon = 0; - if (oldvc == colorplus->cga.crtc[4]) { + if (oldvc == colorplus->cga.crtc[CGA_CRTC_VTOTAL]) { colorplus->cga.vc = 0; - colorplus->cga.vadj = colorplus->cga.crtc[5]; + colorplus->cga.vadj = colorplus->cga.crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!colorplus->cga.vadj) colorplus->cga.cgadispon = 1; if (!colorplus->cga.vadj) - colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[13] | (colorplus->cga.crtc[12] << 8)) & 0x3fff; - if ((colorplus->cga.crtc[10] & 0x60) == 0x20) + colorplus->cga.memaddr = colorplus->cga.memaddr_backup = (colorplus->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (colorplus->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + if ((colorplus->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) colorplus->cga.cursoron = 0; else colorplus->cga.cursoron = colorplus->cga.cgablink & 8; } - if (colorplus->cga.vc == colorplus->cga.crtc[7]) { + if (colorplus->cga.vc == colorplus->cga.crtc[CGA_CRTC_VSYNC]) { colorplus->cga.cgadispon = 0; colorplus->cga.displine = 0; colorplus->cga.vsynctime = 16; - if (colorplus->cga.crtc[7]) { - if (colorplus->cga.cgamode & 1) - x = (colorplus->cga.crtc[1] << 3) + 16; + if (colorplus->cga.crtc[CGA_CRTC_VSYNC]) { + if (colorplus->cga.cgamode & CGA_MODE_FLAG_HIGHRES) + x = (colorplus->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (colorplus->cga.crtc[1] << 4) + 16; + x = (colorplus->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; colorplus->cga.lastline++; if (x != xsize || (colorplus->cga.lastline - colorplus->cga.firstline) != ysize) { xsize = x; @@ -287,15 +291,15 @@ colorplus_poll(void *priv) video_res_x = xsize - 16; video_res_y = ysize; - if (colorplus->cga.cgamode & 1) { + if (colorplus->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; - video_res_y /= colorplus->cga.crtc[9] + 1; + video_res_y /= colorplus->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; video_bpp = 0; - } else if (!(colorplus->cga.cgamode & 2)) { + } else if (!(colorplus->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; - video_res_y /= colorplus->cga.crtc[9] + 1; + video_res_y /= colorplus->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; video_bpp = 0; - } else if (!(colorplus->cga.cgamode & 16)) { + } else if (!(colorplus->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS)) { video_res_x /= 2; video_bpp = 2; } else { @@ -308,17 +312,17 @@ colorplus_poll(void *priv) colorplus->cga.oddeven ^= 1; } } else { - colorplus->cga.sc++; - colorplus->cga.sc &= 31; - colorplus->cga.ma = colorplus->cga.maback; + colorplus->cga.scanline++; + colorplus->cga.scanline &= 31; + colorplus->cga.memaddr = colorplus->cga.memaddr_backup; } if (colorplus->cga.cgadispon) colorplus->cga.cgastat &= ~1; - if (colorplus->cga.sc == (colorplus->cga.crtc[10] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[10] & 31) >> 1))) - colorplus->cga.con = 1; - if (colorplus->cga.cgadispon && (colorplus->cga.cgamode & 1)) { - for (x = 0; x < (colorplus->cga.crtc[1] << 1); x++) - colorplus->cga.charbuffer[x] = colorplus->cga.vram[((colorplus->cga.ma << 1) + x) & 0x3fff]; + if (colorplus->cga.scanline == (colorplus->cga.crtc[CGA_CRTC_CURSOR_START] & 31) || ((colorplus->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && colorplus->cga.scanline == ((colorplus->cga.crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + colorplus->cga.cursorvisible = 1; + if (colorplus->cga.cgadispon && (colorplus->cga.cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (colorplus->cga.crtc[CGA_CRTC_HDISP] << 1); x++) + colorplus->cga.charbuffer[x] = colorplus->cga.vram[((colorplus->cga.memaddr << 1) + x) & 0x3fff]; } } } diff --git a/src/video/vid_cga_comp.c b/src/video/vid_cga_comp.c index 6ad6a6b0a..ca9c2c9df 100644 --- a/src/video/vid_cga_comp.c +++ b/src/video/vid_cga_comp.c @@ -135,7 +135,7 @@ update_cga16_color(uint8_t cgamode) int left = (x >> 6) & 15; int rc = right; int lc = left; - if ((cgamode & 4) != 0) { + if ((cgamode & CGA_MODE_FLAG_BW) != 0) { rc = (right & 8) | ((right & 7) != 0 ? 7 : 0); lc = (left & 8) | ((left & 7) != 0 ? 7 : 0); } @@ -240,7 +240,7 @@ Composite_Process(uint8_t cgamode, uint8_t border, uint32_t blocks /*, bool doub for (uint8_t x = 0; x < 5; ++x) OUT(b[x & 3]); - if ((cgamode & 4) != 0) { + if ((cgamode & CGA_MODE_FLAG_BW) != 0) { /* Decode */ i = temp + 5; srgb = TempLine; diff --git a/src/video/vid_compaq_cga.c b/src/video/vid_cga_compaq.c similarity index 75% rename from src/video/vid_compaq_cga.c rename to src/video/vid_cga_compaq.c index 5b06e23d2..1e21d63c1 100644 --- a/src/video/vid_compaq_cga.c +++ b/src/video/vid_cga_compaq.c @@ -68,9 +68,9 @@ compaq_cga_recalctimings(cga_t *dev) double _dispontime; double _dispofftime; double disptime; - disptime = dev->crtc[0] + 1; + disptime = dev->crtc[CGA_CRTC_HTOTAL] + 1; - _dispontime = dev->crtc[1]; + _dispontime = dev->crtc[CGA_CRTC_HDISP]; _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; @@ -81,24 +81,26 @@ compaq_cga_recalctimings(cga_t *dev) static void compaq_cga_poll(void *priv) { - cga_t *dev = (cga_t *) priv; - uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; - int underline = 0; - int blink = 0; - int drawcursor; - int x; - int c; - int xs_temp; - int ys_temp; - int oldvc; - uint8_t chr; - uint8_t attr; - uint8_t border; - uint8_t cols[4]; - int oldsc; + cga_t *dev = (cga_t *) priv; + uint16_t cursoraddr = (dev->crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (dev->crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; + int drawcursor; + int x; + int c; + int xs_temp; + int ys_temp; + int oldvc; + uint8_t chr; + uint8_t attr; + uint8_t border; + uint8_t cols[4]; + int scanline_old; + int underline = 0; + int blink = 0; + + int32_t highres_graphics_flag = (CGA_MODE_FLAG_HIGHRES_GRAPHICS | CGA_MODE_FLAG_GRAPHICS); /* If in graphics mode or character height is not 13, behave as CGA */ - if ((dev->cgamode & 0x12) || (dev->crtc[9] != 13)) { + if ((dev->cgamode & highres_graphics_flag) || (dev->crtc[CGA_CRTC_MAX_SCANLINE_ADDR] != 13)) { overscan_x = overscan_y = 16; cga_poll(dev); return; @@ -110,9 +112,9 @@ compaq_cga_poll(void *priv) timer_advance_u64(&dev->timer, dev->dispofftime); dev->cgastat |= 1; dev->linepos = 1; - oldsc = dev->sc; - if ((dev->crtc[8] & 3) == 3) - dev->sc = ((dev->sc << 1) + dev->oddeven) & 7; + scanline_old = dev->scanline; + if ((dev->crtc[CGA_CRTC_INTERLACE] & 3) == 3) + dev->scanline = ((dev->scanline << 1) + dev->oddeven) & 7; if (dev->cgadispon) { if (dev->displine < dev->firstline) { dev->firstline = dev->displine; @@ -125,30 +127,30 @@ compaq_cga_poll(void *priv) for (c = 0; c < 8; c++) { buffer32->line[dev->displine][c] = cols[0]; - if (dev->cgamode & 1) - buffer32->line[dev->displine][c + (dev->crtc[1] << 3) + 8] = cols[0]; + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) + buffer32->line[dev->displine][c + (dev->crtc[CGA_CRTC_HDISP] << 3) + 8] = cols[0]; else - buffer32->line[dev->displine][c + (dev->crtc[1] << 4) + 8] = cols[0]; + buffer32->line[dev->displine][c + (dev->crtc[CGA_CRTC_HDISP] << 4) + 8] = cols[0]; } - if (dev->cgamode & 1) { - for (x = 0; x < dev->crtc[1]; x++) { + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) { + for (x = 0; x < dev->crtc[CGA_CRTC_HDISP]; x++) { chr = dev->charbuffer[x << 1]; attr = dev->charbuffer[(x << 1) + 1]; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->memaddr == cursoraddr) && dev->cursorvisible && dev->cursoron); if (vflags) { underline = 0; - blink = ((dev->cgablink & 8) && (dev->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((dev->cgablink & 8) && (dev->cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); } if (vflags && (dev->cgamode & 0x80)) { cols[0] = mdaattr[attr][blink][0]; cols[1] = mdaattr[attr][blink][1]; - if ((dev->sc == 12) && ((attr & 7) == 1)) + if ((dev->scanline == 12) && ((attr & 7) == 1)) underline = 1; - } else if (dev->cgamode & 0x20) { + } else if (dev->cgamode & CGA_MODE_FLAG_BLINK) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; @@ -170,31 +172,31 @@ compaq_cga_poll(void *priv) } else if (drawcursor) { for (c = 0; c < 8; c++) buffer32->line[dev->displine][(x << 3) + c + 8] = - cols[(fontdatm[chr + dev->fontbase][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + cols[(fontdatm[chr + dev->fontbase][dev->scanline & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) buffer32->line[dev->displine][(x << 3) + c + 8] = - cols[(fontdatm[chr + dev->fontbase][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + cols[(fontdatm[chr + dev->fontbase][dev->scanline & 15] & (1 << (c ^ 7))) ? 1 : 0]; } - dev->ma++; + dev->memaddr++; } } else { - for (x = 0; x < dev->crtc[1]; x++) { - chr = dev->vram[(dev->ma << 1) & 0x3fff]; - attr = dev->vram[((dev->ma << 1) + 1) & 0x3fff]; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + for (x = 0; x < dev->crtc[CGA_CRTC_HDISP]; x++) { + chr = dev->vram[(dev->memaddr << 1) & 0x3fff]; + attr = dev->vram[((dev->memaddr << 1) + 1) & 0x3fff]; + drawcursor = ((dev->memaddr == cursoraddr) && dev->cursorvisible && dev->cursoron); if (vflags) { underline = 0; - blink = ((dev->cgablink & 8) && (dev->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((dev->cgablink & 8) && (dev->cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); } if (vflags && (dev->cgamode & 0x80)) { cols[0] = mdaattr[attr][blink][0]; cols[1] = mdaattr[attr][blink][1]; - if (dev->sc == 12 && (attr & 7) == 1) + if (dev->scanline == 12 && (attr & 7) == 1) underline = 1; - } else if (dev->cgamode & 0x20) { + } else if (dev->cgamode & CGA_MODE_FLAG_BLINK) { cols[1] = (attr & 15) + 16; cols[0] = ((attr >> 4) & 7) + 16; @@ -209,7 +211,7 @@ compaq_cga_poll(void *priv) cols[1] = (attr & 15) + 16; cols[0] = (attr >> 4) + 16; } - dev->ma++; + dev->memaddr++; if (vflags && underline) { for (c = 0; c < 8; c++) @@ -219,31 +221,31 @@ compaq_cga_poll(void *priv) for (c = 0; c < 8; c++) buffer32->line[dev->displine][(x << 4) + (c << 1) + 8] = buffer32->line[dev->displine][(x << 4) + (c << 1) + 1 + 8] = - cols[(fontdatm[chr + dev->fontbase][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + cols[(fontdatm[chr + dev->fontbase][dev->scanline & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) buffer32->line[dev->displine][(x << 4) + (c << 1) + 8] = buffer32->line[dev->displine][(x << 4) + (c << 1) + 1 + 8] = - cols[(fontdatm[chr + dev->fontbase][dev->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + cols[(fontdatm[chr + dev->fontbase][dev->scanline & 15] & (1 << (c ^ 7))) ? 1 : 0]; } } } } else { cols[0] = (dev->cgacol & 15) + 16; - if (dev->cgamode & 1) - hline(buffer32, 0, dev->displine, (dev->crtc[1] << 3) + 16, cols[0]); + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) + hline(buffer32, 0, dev->displine, (dev->crtc[CGA_CRTC_HDISP] << 3) + 16, cols[0]); else - hline(buffer32, 0, dev->displine, (dev->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, dev->displine, (dev->crtc[CGA_CRTC_HDISP] << 4) + 16, cols[0]); } - if (dev->cgamode & 1) - x = (dev->crtc[1] << 3) + 16; + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (dev->crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (dev->crtc[1] << 4) + 16; + x = (dev->crtc[CGA_CRTC_HDISP] << 4) + 16; if (dev->composite) { - if (dev->cgamode & 0x10) + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) border = 0x00; else border = dev->cgacol & 0x0f; @@ -255,8 +257,8 @@ compaq_cga_poll(void *priv) } else video_process_8(x, dev->displine); - dev->sc = oldsc; - if (dev->vc == dev->crtc[7] && !dev->sc) + dev->scanline = scanline_old; + if (dev->vc == dev->crtc[CGA_CRTC_VSYNC] && !dev->scanline) dev->cgastat |= 8; dev->displine++; if (dev->displine >= 500) @@ -270,28 +272,27 @@ compaq_cga_poll(void *priv) dev->cgastat &= ~8; } - if (dev->sc == (dev->crtc[11] & 31) || (((dev->crtc[8] & 3) == 3) && - (dev->sc == ((dev->crtc[11] & 31) >> 1)))) { - dev->con = 0; + if (dev->scanline == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->scanline == ((dev->crtc[11] & 31) >> 1))) { + dev->cursorvisible = 0; } - if ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1)) - dev->maback = dev->ma; + if ((dev->crtc[8] & 3) == 3 && dev->scanline == (dev->crtc[9] >> 1)) + dev->memaddr_backup = dev->memaddr; if (dev->vadj) { - dev->sc++; - dev->sc &= 31; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 31; + dev->memaddr = dev->memaddr_backup; dev->vadj--; if (!dev->vadj) { dev->cgadispon = 1; - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; - dev->sc = 0; + dev->memaddr = dev->memaddr_backup = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->scanline = 0; } - } else if (dev->sc == dev->crtc[9]) { - dev->maback = dev->ma; - dev->sc = 0; - oldvc = dev->vc; + } else if (dev->scanline == dev->crtc[9]) { + dev->memaddr_backup = dev->memaddr; + dev->scanline = 0; + oldvc = dev->vc; dev->vc++; - dev->vc &= 127; + dev->vc &= 127; if (dev->vc == dev->crtc[6]) dev->cgadispon = 0; @@ -304,7 +305,7 @@ compaq_cga_poll(void *priv) dev->cgadispon = 1; if (!dev->vadj) - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->memaddr = dev->memaddr_backup = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; if ((dev->crtc[10] & 0x60) == 0x20) dev->cursoron = 0; @@ -321,10 +322,10 @@ compaq_cga_poll(void *priv) compaq_cga_log("Lastline %i Firstline %i %i\n", dev->lastline, dev->firstline, dev->lastline - dev->firstline); - if (dev->cgamode & 1) - x = (dev->crtc[1] << 3) + 16; + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) + x = (dev->crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (dev->crtc[1] << 4) + 16; + x = (dev->crtc[CGA_CRTC_HDISP] << 4) + 16; dev->lastline++; @@ -339,8 +340,7 @@ compaq_cga_poll(void *priv) if (!enable_overscan) xs_temp -= 16; - if ((dev->cgamode & 8) && ((xs_temp != xsize) || - (ys_temp != ysize) || video_force_resize_get())) { + if ((dev->cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { xsize = xs_temp; ysize = ys_temp; set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); @@ -361,7 +361,7 @@ compaq_cga_poll(void *priv) if (enable_overscan) xsize -= 16; video_res_y = ysize; - if (dev->cgamode & 1) { + if (dev->cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; video_res_y /= dev->crtc[9] + 1; video_bpp = 0; @@ -382,21 +382,20 @@ compaq_cga_poll(void *priv) dev->oddeven ^= 1; } } else { - dev->sc++; - dev->sc &= 31; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 31; + dev->memaddr = dev->memaddr_backup; } if (dev->cgadispon) dev->cgastat &= ~1; - if (dev->sc == (dev->crtc[10] & 31) || - (((dev->crtc[8] & 3) == 3) && (dev->sc == ((dev->crtc[10] & 31) >> 1)))) - dev->con = 1; + if (dev->scanline == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->scanline == ((dev->crtc[10] & 31) >> 1))) + dev->cursorvisible = 1; - if (dev->cgadispon && (dev->cgamode & 1)) { - for (x = 0; x < (dev->crtc[1] << 1); x++) - dev->charbuffer[x] = dev->vram[((dev->ma << 1) + x) & 0x3fff]; + if (dev->cgadispon && (dev->cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (dev->crtc[CGA_CRTC_HDISP] << 1); x++) + dev->charbuffer[x] = dev->vram[((dev->memaddr << 1) + x) & 0x3fff]; } } } @@ -475,8 +474,7 @@ compaq_cga_speed_changed(void *priv) { cga_t *dev = (cga_t *) priv; - if (dev->crtc[9] == 13) - /* Character height */ + if (dev->crtc[9] == 13) /* Character height */ compaq_cga_recalctimings(dev); else cga_recalctimings(dev); diff --git a/src/video/vid_cga_compaq_plasma.c b/src/video/vid_cga_compaq_plasma.c new file mode 100644 index 000000000..b281cf93f --- /dev/null +++ b/src/video/vid_cga_compaq_plasma.c @@ -0,0 +1,843 @@ +/* + * 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 the plasma displays on early Compaq Portables and laptops. + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2020 Sarah Walker. + * Copyright 2016-2020 Miran Grca. + * Copyright 2025 starfrost + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include "cpu.h" +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/pit.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/video.h> +#include <86box/vid_cga.h> +#include <86box/vid_cga_comp.h> +#include <86box/plat_unused.h> + +static video_timings_t timing_compaq_plasma = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +/*Very rough estimate*/ +#define VID_CLOCK (double) (651 * 416 * 60) + +/* Mapping of attributes to colours */ +static uint32_t amber; +static uint32_t black; +static uint32_t blinkcols[256][2]; +static uint32_t normcols[256][2]; + +/* Video options set by the motherboard; they will be picked up by the card + * on the next poll. + * + * Bit 3: Disable built-in video (for add-on card) + * Bit 2: Thin font + * Bits 0,1: Font set (not currently implemented) + */ +static int8_t cpq_st_display_internal = -1; + +static uint8_t mdaattr[256][2][2]; + +static void +compaq_plasma_display_set(uint8_t internal) +{ + cpq_st_display_internal = internal; +} + +typedef struct compaq_plasma_t { + cga_t cga; + mem_mapping_t font_ram_mapping; + uint8_t *font_ram; + uint8_t port_13c6; + uint8_t port_23c6; + uint8_t port_27c6; + uint8_t internal_monitor; +} compaq_plasma_t; + + +static void compaq_plasma_recalcattrs(compaq_plasma_t *self); + +static void +compaq_plasma_recalctimings(compaq_plasma_t *self) +{ + double _dispontime; + double _dispofftime; + double disptime; + + if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { + cga_recalctimings(&self->cga); + return; + } + + disptime = 651; + _dispontime = 640; + _dispofftime = disptime - _dispontime; + self->cga.dispontime = (uint64_t) (_dispontime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); + self->cga.dispofftime = (uint64_t) (_dispofftime * (cpuclock / VID_CLOCK) * (double) (1ULL << 32)); +} + +static void +compaq_plasma_waitstates(UNUSED(void *priv)) +{ + int ws_array[16] = { 3, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8, 4, 5, 6, 7, 8 }; + int ws; + + ws = ws_array[cycles & 0xf]; + sub_cycles(ws); +} + +static void +compaq_plasma_write(uint32_t addr, uint8_t val, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + + if (self->port_23c6 & 0x08) + self->font_ram[addr & 0x1fff] = val; + else + self->cga.vram[addr & 0x7fff] = val; + + compaq_plasma_waitstates(&self->cga); +} +static uint8_t +compaq_plasma_read(uint32_t addr, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + uint8_t ret; + + compaq_plasma_waitstates(&self->cga); + + if (self->port_23c6 & 0x08) + ret = (self->font_ram[addr & 0x1fff]); + else + ret = (self->cga.vram[addr & 0x7fff]); + + return ret; +} + +static void +compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + + switch (addr) { + /* Emulated CRTC, register select */ + case 0x3d0: + case 0x3d2: + case 0x3d4: + case 0x3d6: + cga_out(addr, val, &self->cga); + break; + + /* Emulated CRTC, value */ + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + cga_out(addr, val, &self->cga); + compaq_plasma_recalctimings(self); + break; + case 0x3d8: + case 0x3d9: + cga_out(addr, val, &self->cga); + break; + + case 0x13c6: + self->port_13c6 = val; + compaq_plasma_display_set((self->port_13c6 & 0x08) ? 1 : 0); + /* + For bits 2-0, John gives 0 = CGA, 1 = EGA, 3 = MDA; + Another source (Ralf Brown?) gives 4 = CGA, 5 = EGA, 7 = MDA; + This leads me to believe bit 2 is not relevant to the mode. + */ + if ((val & 0x07) == 0x03) + mem_mapping_set_addr(&self->cga.mapping, 0xb0000, 0x08000); + else + mem_mapping_set_addr(&self->cga.mapping, 0xb8000, 0x08000); + break; + + case 0x23c6: + self->port_23c6 = val; + break; + + case 0x27c6: + self->port_27c6 = val; + break; + + default: + break; + } +} + +static uint8_t +compaq_plasma_in(uint16_t addr, void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3d4: + case 0x3da: + case 0x3db: + case 0x3dc: + ret = cga_in(addr, &self->cga); + break; + + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + ret = cga_in(addr, &self->cga); + break; + + case 0x3d8: + ret = self->cga.cgamode; + break; + + case 0x13c6: + ret = self->port_13c6; + break; + + case 0x17c6: + ret = 0xe6; + break; + + case 0x1bc6: + ret = 0x40; + break; + + case 0x23c6: + ret = self->port_23c6; + break; + + case 0x27c6: + ret = self->port_27c6 & 0x3f; + break; + + default: + break; + } + + return ret; +} + +static void +compaq_plasma_poll(void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + uint8_t chr; + uint8_t attr; + uint8_t scanline; + uint16_t memaddr = (self->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (self->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; + uint16_t cursoraddr = (self->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (self->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x7fff; + uint16_t addr; + int drawcursor; + int cursorline; + int blink = 0; + int underline = 0; + int cursorvisible = 0; + int cursorinvisible = 0; + int c; + int x; + uint32_t ink = 0; + uint32_t fg = (self->cga.cgacol & 0x0f) ? amber : black; + uint32_t bg = black; + uint32_t black_half = black; + uint32_t amber_half = amber; + uint32_t cols[2]; + uint8_t dat; + uint8_t pattern; + uint32_t ink0 = 0; + uint32_t ink1 = 0; + + /* Switch between internal plasma and external CRT display. */ + if ((cpq_st_display_internal != -1) && (cpq_st_display_internal != self->internal_monitor)) { + self->internal_monitor = cpq_st_display_internal; + compaq_plasma_recalctimings(self); + } + + /* graphic mode and not mode 40h */ + if (!self->internal_monitor && !(self->port_23c6 & 0x01)) { + /* standard cga mode */ + cga_poll(&self->cga); + return; + } else { + /* mode 40h or text mode */ + if (!self->cga.linepos) { + timer_advance_u64(&self->cga.timer, self->cga.dispofftime); + self->cga.cgastat |= 1; + self->cga.linepos = 1; + if (self->cga.cgadispon) { + if (self->cga.displine == 0) + video_wait_for_buffer(); + + /* 80-col */ + if (self->cga.cgamode & 0x01) { + scanline = self->cga.displine & 0x0f; + addr = ((memaddr & ~1) + (self->cga.displine >> 4) * 80) << 1; + memaddr += (self->cga.displine >> 4) * 80; + + if ((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) + cursorline = 0; + else { + if ((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0f) > 0x07) + cursorvisible = (self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0f) + 1; + else + cursorvisible = ((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0f) << 1); + + if ((self->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0f) > 0x07) + cursorinvisible = (self->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0f) + 2; + else + cursorinvisible = ((self->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0f) << 1); + + cursorline = (cursorvisible <= scanline) && (cursorinvisible >= scanline); + } + + /* for each text column */ + for (x = 0; x < 80; x++) { + /* video output enabled */ + if (self->cga.cgamode & 0x08) { + /* character */ + chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; + /* text attributes */ + attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; + } else { + chr = 0x00; + attr = 0x00; + } + + uint8_t hi_bit = attr & 0x08; + /* check if cursor has to be drawn */ + drawcursor = ((memaddr == cursoraddr) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); + /* check if character underline mode should be set */ + underline = ((attr & 0x07) == 0x01); + underline = underline || (((self->port_23c6 >> 5) == 1) && hi_bit); + if (underline) { + /* set forecolor to white */ + attr = attr | 0x7; + } + blink = 0; + /* set foreground */ + cols[1] = blinkcols[attr][1]; + /* blink active */ + if (self->cga.cgamode & CGA_MODE_FLAG_BLINK) { + cols[0] = blinkcols[attr][0]; + /* attribute 7 active and not cursor */ + if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + blink = 1; + } + } else { + /* Set intensity bit */ + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + + /* character address */ + uint16_t chr_addr = ((chr * 16) + scanline) & 0x0fff; + if (((self->port_23c6 >> 5) == 3) && hi_bit) + chr_addr |= 0x1000; + + /* character underline active and 7th row of pixels in character height being drawn */ + if (underline) { + /* for each pixel in character width */ + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; + } + + if (hi_bit) { + if ((self->port_23c6 >> 5) == 4) { + uint8_t b = (cols[1] & 0xff) >> 1; + uint8_t g = ((cols[1] >> 8) & 0xff) >> 1; + uint8_t r = ((cols[1] >> 16) & 0xff) >> 1; + cols[1] = b | (g << 8) | (r << 16); + b = (cols[0] & 0xff) >> 1; + g = ((cols[0] >> 8) & 0xff) >> 1; + r = ((cols[0] >> 16) & 0xff) >> 1; + cols[0] = b | (g << 8) | (r << 16); + if (drawcursor) { + black_half = black; + amber_half = amber; + uint8_t bB = (black & 0xff) >> 1; + uint8_t gB = ((black >> 8) & 0xff) >> 1; + uint8_t rB = ((black >> 16) & 0xff) >> 1; + black_half = bB | (gB << 8) | (rB << 16); + uint8_t bA = (amber & 0xff) >> 1; + uint8_t gA = ((amber >> 8) & 0xff) >> 1; + uint8_t rA = ((amber >> 16) & 0xff) >> 1; + amber_half = bA | (gA << 8) | (rA << 16); + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber_half ^ black_half); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; + } + } else if ((self->port_23c6 >> 5) == 2) { + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 0 : 1] ^ (amber ^ black); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 3) + c] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 0 : 1]; + } + } + } + memaddr++; + } + } + /* 40-col */ + else if (!(self->cga.cgamode & 0x02)) { + scanline = self->cga.displine & 0x0f; + addr = ((memaddr & ~1) + (self->cga.displine >> 4) * 40) << 1; + memaddr += (self->cga.displine >> 4) * 40; + + if ((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) + cursorline = 0; + else { + if ((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0f) > 0x07) + cursorvisible = (self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0f) + 1; + else + cursorvisible = ((self->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0f) << 1); + + if ((self->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0f) > 0x07) + cursorinvisible = (self->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0f) + 2; + else + cursorinvisible = ((self->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0f) << 1); + + cursorline = (cursorvisible <= scanline) && (cursorinvisible >= scanline); + } + + for (x = 0; x < 40; x++) { + /* video output enabled */ + if (self->cga.cgamode & 0x08) { + /* character */ + chr = self->cga.vram[(addr + (x << 1)) & 0x7fff]; + /* text attributes */ + attr = self->cga.vram[(addr + ((x << 1) + 1)) & 0x7fff]; + } else { + chr = 0x00; + attr = 0x00; + } + + uint8_t hi_bit = attr & 0x08; + /* check if cursor has to be drawn */ + drawcursor = ((memaddr == cursoraddr) && cursorline && (self->cga.cgamode & 0x08) && (self->cga.cgablink & 0x10)); + /* check if character underline mode should be set */ + underline = ((attr & 0x07) == 0x01); + underline = underline || (((self->port_23c6 >> 5) == 1) && hi_bit); + if (underline) { + /* set forecolor to white */ + attr = attr | 0x7; + } + blink = 0; + /* set foreground */ + cols[1] = blinkcols[attr][1]; + /* blink active */ + if (self->cga.cgamode & CGA_MODE_FLAG_BLINK) { + cols[0] = blinkcols[attr][0]; + /* attribute 7 active and not cursor */ + if ((self->cga.cgablink & 0x08) && (attr & 0x80) && !drawcursor) { + /* set blinking */ + cols[1] = cols[0]; + blink = 1; + } + } else { + /* Set intensity bit */ + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + + /* character address */ + uint16_t chr_addr = ((chr * 16) + scanline) & 0x0fff; + if (((self->port_23c6 >> 5) == 3) && hi_bit) + chr_addr |= 0x1000; + + /* character underline active and 7th row of pixels in character height being drawn */ + if (underline && (scanline == 7)) { + /* for each pixel in character width */ + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = mdaattr[attr][blink][1]; + } else if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; + } + + if (hi_bit) { + if ((self->port_23c6 >> 5) == 4) { + uint8_t b = (cols[1] & 0xff) >> 1; + uint8_t g = ((cols[1] >> 8) & 0xff) >> 1; + uint8_t r = ((cols[1] >> 16) & 0xff) >> 1; + cols[1] = b | (g << 8) | (r << 16); + b = (cols[0] & 0xff) >> 1; + g = ((cols[0] >> 8) & 0xff) >> 1; + r = ((cols[0] >> 16) & 0xff) >> 1; + cols[0] = b | (g << 8) | (r << 16); + if (drawcursor) { + black_half = black; + amber_half = amber; + uint8_t bB = (black & 0xff) >> 1; + uint8_t gB = ((black >> 8) & 0xff) >> 1; + uint8_t rB = ((black >> 16) & 0xff) >> 1; + black_half = bB | (gB << 8) | (rB << 16); + uint8_t bA = (amber & 0xff) >> 1; + uint8_t gA = ((amber >> 8) & 0xff) >> 1; + uint8_t rA = ((amber >> 16) & 0xff) >> 1; + amber_half = bA | (gA << 8) | (rA << 16); + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber_half ^ black_half); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 1 : 0]; + } + } else if ((self->port_23c6 >> 5) == 2) { + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 0 : 1] ^ (amber ^ black); + } else { + for (c = 0; c < 8; c++) + buffer32->line[self->cga.displine][(x << 4) + (c << 1)] = buffer32->line[self->cga.displine][(x << 4) + (c << 1) + 1] = cols[(self->font_ram[chr_addr] & (1 << (c ^ 7))) ? 0 : 1]; + } + } + } + memaddr++; + } + } else { + if (self->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) { + /* 640x400 mode */ + if (self->port_23c6 & 0x01) /* 640*400 */ { + addr = ((self->cga.displine) & 1) * 0x2000 + ((self->cga.displine >> 1) & 1) * 0x4000 + (self->cga.displine >> 2) * 80 + ((memaddr & ~1) << 1); + } else { + addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((memaddr & ~1) << 1); + } + for (uint8_t x = 0; x < 80; x++) { + dat = self->cga.vram[addr & 0x7fff]; + addr++; + + for (uint8_t c = 0; c < 8; c++) { + ink = (dat & 0x80) ? fg : bg; + if (!(self->cga.cgamode & 0x08)) + ink = black; + buffer32->line[self->cga.displine][(x << 3) + c] = ink; + dat <<= 1; + } + } + } else { + addr = ((self->cga.displine >> 1) & 1) * 0x2000 + (self->cga.displine >> 2) * 80 + ((memaddr & ~1) << 1); + for (uint8_t x = 0; x < 80; x++) { + dat = self->cga.vram[addr & 0x7fff]; + addr++; + + for (uint8_t c = 0; c < 4; c++) { + pattern = (dat & 0xC0) >> 6; + if (!(self->cga.cgamode & 0x08)) + pattern = 0; + + switch (pattern & 3) { + case 0: + ink0 = ink1 = black; + break; + case 1: + if (self->cga.displine & 0x01) { + ink0 = black; + ink1 = black; + } else { + ink0 = amber; + ink1 = black; + } + break; + case 2: + if (self->cga.displine & 0x01) { + ink0 = black; + ink1 = amber; + } else { + ink0 = amber; + ink1 = black; + } + break; + case 3: + ink0 = ink1 = amber; + break; + + default: + break; + } + buffer32->line[self->cga.displine][(x << 3) + (c << 1)] = ink0; + buffer32->line[self->cga.displine][(x << 3) + (c << 1) + 1] = ink1; + dat <<= 2; + } + } + } + } + } + self->cga.displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (self->cga.displine == 400) { /* Start of VSYNC */ + self->cga.cgastat |= 8; + self->cga.cgadispon = 0; + } + if (self->cga.displine == 416) { /* End of VSYNC */ + self->cga.displine = 0; + self->cga.cgastat &= ~8; + self->cga.cgadispon = 1; + } + } else { + timer_advance_u64(&self->cga.timer, self->cga.dispontime); + if (self->cga.cgadispon) + self->cga.cgastat &= ~1; + + self->cga.linepos = 0; + + if (self->cga.displine == 400) { + xsize = 640; + ysize = 400; + + if ((self->cga.cgamode & 0x08) || video_force_resize_get()) { + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + /* Plasma specific */ + video_blit_memtoscreen(0, 0, xsize, ysize); + frames++; + + /* Fixed 640x400 resolution */ + video_res_x = 640; + video_res_y = 400; + + if (self->cga.cgamode & 0x02) { + if (self->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) + video_bpp = 1; + else + video_bpp = 2; + } else + video_bpp = 0; + + self->cga.cgablink++; + } + } + } +} + +static void +compaq_plasma_mdaattr_rebuild(void) +{ + for (uint16_t c = 0; c < 256; c++) { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; + if (c & 8) + mdaattr[c][0][1] = 15 + 16; + else + mdaattr[c][0][1] = 7 + 16; + } + + mdaattr[0x70][0][1] = 16; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; + mdaattr[0xF0][0][1] = 16; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; + mdaattr[0x78][0][1] = 16 + 7; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; + mdaattr[0xF8][0][1] = 16 + 7; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; +} + +static void +compaq_plasma_recalcattrs(compaq_plasma_t *self) +{ + int n; + + /* val behaves as follows: + * Bit 0: Attributes 01-06, 08-0E are inverse video + * Bit 1: Attributes 01-06, 08-0E are bold + * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF + * are inverse video + * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF + * are bold */ + + /* Set up colours */ + amber = makecol(0xff, 0x7d, 0x00); + black = makecol(0x64, 0x19, 0x00); + + /* Initialize the attribute mapping. Start by defaulting everything + * to black on amber, and with bold set by bit 3 */ + for (n = 0; n < 256; n++) { + blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][1] = normcols[n][1] = black; + } + + /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the + * passed value. Exclude x0 and x8, which are always black on + * amber. */ + for (n = 0x11; n <= 0xFF; n++) { + if ((n & 7) == 0) + continue; + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + } + /* Set up the 01-0E range, controlled by bits 0 and 1 of the + * passed value. When blinking is enabled this also affects 81-8E. */ + for (n = 0x01; n <= 0x0E; n++) { + if (n == 7) + continue; + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + blinkcols[n + 128][0] = black; + blinkcols[n + 128][1] = amber; + } + /* Colours 07 and 0F are always amber on black. If blinking is + * enabled so are 87 and 8F. */ + for (n = 0x07; n <= 0x0F; n += 8) { + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + blinkcols[n + 128][0] = black; + blinkcols[n + 128][1] = amber; + } + /* When not blinking, colours 81-8F are always amber on black. */ + for (n = 0x81; n <= 0x8F; n++) { + normcols[n][0] = black; + normcols[n][1] = amber; + } + + /* Finally do the ones which are solid black. These differ between + * the normal and blinking mappings */ + for (n = 0; n <= 0xFF; n += 0x11) + normcols[n][0] = normcols[n][1] = black; + + /* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are black */ + for (n = 0; n <= 0x77; n += 0x11) { + blinkcols[n][0] = blinkcols[n][1] = black; + blinkcols[n + 128][0] = blinkcols[n + 128][1] = black; + } +} + +static void * +compaq_plasma_init(UNUSED(const device_t *info)) +{ + compaq_plasma_t *self = calloc(1, sizeof(compaq_plasma_t)); + + cga_init(&self->cga); + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_compaq_plasma); + + self->cga.composite = 0; + self->cga.revision = 0; + + self->cga.vram = malloc(0x8000); + self->internal_monitor = 1; + self->font_ram = malloc(0x2000); + + cga_comp_init(self->cga.revision); + timer_set_callback(&self->cga.timer, compaq_plasma_poll); + timer_set_p(&self->cga.timer, self); + + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, + compaq_plasma_read, NULL, NULL, + compaq_plasma_write, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, self); + for (int i = 1; i <= 2; i++) { + io_sethandler(0x03c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + io_sethandler(0x07c6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + io_sethandler(0x0bc6 + (i << 12), 0x0001, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + } + io_sethandler(0x03d0, 0x0010, compaq_plasma_in, NULL, NULL, compaq_plasma_out, NULL, NULL, self); + + overscan_x = overscan_y = 16; + compaq_plasma_recalcattrs(self); + + self->cga.rgb_type = device_get_config_int("rgb_type"); + cga_palette = (self->cga.rgb_type << 1); + cgapal_rebuild(); + compaq_plasma_mdaattr_rebuild(); + + return self; +} + +static void +compaq_plasma_close(void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + + free(self->cga.vram); + free(self->font_ram); + free(self); +} + +static void +compaq_plasma_speed_changed(void *priv) +{ + compaq_plasma_t *self = (compaq_plasma_t *) priv; + + compaq_plasma_recalctimings(self); +} + +const device_config_t compaq_plasma_config[] = { + // clang-format off + { + .name = "rgb_type", + .description = "RGB type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = 0, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "Color", .value = 0 }, + { .description = "Green Monochrome", .value = 1 }, + { .description = "Amber Monochrome", .value = 2 }, + { .description = "Gray Monochrome", .value = 3 }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t compaq_plasma_device = { + .name = "Compaq Plasma", + .internal_name = "compaq_plasma", + .flags = 0, + .local = 0, + .init = compaq_plasma_init, + .close = compaq_plasma_close, + .reset = NULL, + .available = NULL, + .speed_changed = compaq_plasma_speed_changed, + .force_redraw = NULL, + .config = compaq_plasma_config +}; diff --git a/src/video/vid_nga.c b/src/video/vid_cga_ncr.c similarity index 74% rename from src/video/vid_nga.c rename to src/video/vid_cga_ncr.c index 5fc81109c..eb4474a40 100644 --- a/src/video/vid_nga.c +++ b/src/video/vid_cga_ncr.c @@ -56,12 +56,12 @@ nga_recalctimings(nga_t *nga) double _dispofftime; double disptime; - if (nga->cga.cgamode & 1) { - disptime = nga->cga.crtc[0] + 1; - _dispontime = nga->cga.crtc[1]; + if (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { + disptime = nga->cga.crtc[CGA_CRTC_HTOTAL] + 1; + _dispontime = nga->cga.crtc[CGA_CRTC_HDISP]; } else { - disptime = (nga->cga.crtc[0] + 1) << 1; - _dispontime = nga->cga.crtc[1] << 1; + disptime = (nga->cga.crtc[CGA_CRTC_HTOTAL] + 1) << 1; + _dispontime = nga->cga.crtc[CGA_CRTC_HDISP] << 1; } _dispofftime = disptime - _dispontime; @@ -148,7 +148,7 @@ nga_poll(void *priv) { nga_t *nga = (nga_t *) priv; /* set cursor position in memory */ - uint16_t ca = (nga->cga.crtc[15] | (nga->cga.crtc[14] << 8)) & 0x3fff; + uint16_t cursoraddr = (nga->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (nga->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; int drawcursor; int x; int c; @@ -161,10 +161,10 @@ nga_poll(void *priv) uint16_t dat2; int cols[4]; int col; - int oldsc; + int scanline_old; /* graphic mode and not high-res modes */ - if ((nga->cga.cgamode & 2) && !(nga->cga.cgamode & 0x40)) { + if ((nga->cga.cgamode & CGA_MODE_FLAG_GRAPHICS) && !(nga->cga.cgamode & 0x40)) { /* standard cga mode */ cga_poll(&nga->cga); return; @@ -174,10 +174,10 @@ nga_poll(void *priv) timer_advance_u64(&nga->cga.timer, nga->cga.dispofftime); nga->cga.cgastat |= 1; nga->cga.linepos = 1; - oldsc = nga->cga.sc; + scanline_old = nga->cga.scanline; /* if interlaced */ - if ((nga->cga.crtc[8] & 3) == 3) - nga->cga.sc = ((nga->cga.sc << 1) + nga->cga.oddeven) & 7; + if ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3) + nga->cga.scanline = ((nga->cga.scanline << 1) + nga->cga.oddeven) & 7; if (nga->cga.cgadispon) { if (nga->cga.displine < nga->cga.firstline) { nga->cga.firstline = nga->cga.displine; @@ -185,11 +185,11 @@ nga_poll(void *priv) } nga->cga.lastline = nga->cga.displine; /* 80-col */ - if ((nga->cga.cgamode & 1) && !(nga->cga.cgamode & 2)) { + if ((nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) && !(nga->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { /* for each text column */ - for (x = 0; x < nga->cga.crtc[1]; x++) { + for (x = 0; x < nga->cga.crtc[CGA_CRTC_HDISP]; x++) { /* video output enabled */ - if (nga->cga.cgamode & 8) { + if (nga->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { /* character */ chr = nga->cga.charbuffer[x << 1]; /* text attributes */ @@ -197,11 +197,11 @@ nga_poll(void *priv) } else chr = attr = 0; /* check if cursor has to be drawn */ - drawcursor = ((nga->cga.ma == ca) && nga->cga.con && nga->cga.cursoron); + drawcursor = ((nga->cga.memaddr == cursoraddr) && nga->cga.cursorvisible && nga->cga.cursoron); /* set foreground */ cols[1] = (attr & 15) + 16; /* blink active */ - if (nga->cga.cgamode & 0x20) { + if (nga->cga.cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; /* attribute 7 active and not cursor */ if ((nga->cga.cgablink & 8) && (attr & 0x80) && !nga->cga.drawcursor) { @@ -214,30 +214,30 @@ nga_poll(void *priv) } if (drawcursor) { for (c = 0; c < 8; c++) - buffer32->line[nga->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((nga->cga.sc & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + buffer32->line[nga->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((nga->cga.scanline & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - buffer32->line[nga->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((nga->cga.sc & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[nga->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((nga->cga.scanline & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0]; } - nga->cga.ma++; + nga->cga.memaddr++; } } /* 40-col */ - else if (!(nga->cga.cgamode & 2)) { + else if (!(nga->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { /* for each text column */ - for (x = 0; x < nga->cga.crtc[1]; x++) { - if (nga->cga.cgamode & 8) { - chr = nga->cga.vram[((nga->cga.ma << 1) & 0x3fff) + nga->base]; - attr = nga->cga.vram[(((nga->cga.ma << 1) + 1) & 0x3fff) + nga->base]; + for (x = 0; x < nga->cga.crtc[CGA_CRTC_HDISP]; x++) { + if (nga->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { + chr = nga->cga.vram[((nga->cga.memaddr << 1) & 0x3fff) + nga->base]; + attr = nga->cga.vram[(((nga->cga.memaddr << 1) + 1) & 0x3fff) + nga->base]; } else { chr = attr = 0; } - drawcursor = ((nga->cga.ma == ca) && nga->cga.con && nga->cga.cursoron); + drawcursor = ((nga->cga.memaddr == cursoraddr) && nga->cga.cursorvisible && nga->cga.cursoron); /* set foreground */ cols[1] = (attr & 15) + 16; /* blink active */ - if (nga->cga.cgamode & 0x20) { + if (nga->cga.cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; if ((nga->cga.cgablink & 8) && (attr & 0x80) && !nga->cga.drawcursor) { /* set blinking */ @@ -250,19 +250,19 @@ nga_poll(void *priv) if (drawcursor) { for (c = 0; c < 8; c++) - buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((nga->cga.sc & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((nga->cga.scanline & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((nga->cga.sc & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[nga->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((nga->cga.scanline & 7) << 1) | nga->lineff] & (1 << (c ^ 7))) ? 1 : 0]; } - nga->cga.ma++; + nga->cga.memaddr++; } } else { /* high res modes */ if (nga->cga.cgamode & 0x40) { /* 640x400x2 mode */ - if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & 0x10) { + if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) { /* * Scanlines are read in the following order: * 0b8000-0b9f3f even scans (0,4,...) @@ -270,14 +270,14 @@ nga_poll(void *priv) * 0bc000-0bdf3f even scans (1,5,...) * 0be000-0bff3f odd scans (3,7,...) */ - dat2 = ((nga->cga.sc & 1) * 0x2000) | (nga->lineff * 0x4000); + dat2 = ((nga->cga.scanline & 1) * 0x2000) | (nga->lineff * 0x4000); cols[0] = 0; cols[1] = 15 + 16; /* 640x400x4 mode */ } else { cols[0] = (nga->cga.cgacol & 15) | 16; col = (nga->cga.cgacol & 16) ? 24 : 16; - if (nga->cga.cgamode & 4) { + if (nga->cga.cgamode & CGA_MODE_FLAG_BW) { cols[1] = col | 3; /* Cyan */ cols[2] = col | 4; /* Red */ cols[3] = col | 7; /* White */ @@ -297,22 +297,22 @@ nga_poll(void *priv) * 0a8000-0abf3f even scans (2,6,...) * 0ac000-0aff3f odd scans (3,7,...) */ - dat2 = (nga->cga.sc & 1) * 0x4000; + dat2 = (nga->cga.scanline & 1) * 0x4000; } } else { - dat2 = (nga->cga.sc & 1) * 0x2000; + dat2 = (nga->cga.scanline & 1) * 0x2000; cols[0] = 0; cols[1] = (nga->cga.cgacol & 15) + 16; } /* for each text column */ - for (x = 0; x < nga->cga.crtc[1]; x++) { + for (x = 0; x < nga->cga.crtc[CGA_CRTC_HDISP]; x++) { /* video out */ - if (nga->cga.cgamode & 8) { + if (nga->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { /* 640x400x2 */ - if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & 0x10) { + if (nga->cga.cgamode & 0x4 || nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) { /* read two bytes at a time */ - dat = (nga->cga.vram[((nga->cga.ma << 1) & 0x1fff) + dat2] << 8) | nga->cga.vram[((nga->cga.ma << 1) & 0x1fff) + dat2 + 1]; + dat = (nga->cga.vram[((nga->cga.memaddr << 1) & 0x1fff) + dat2] << 8) | nga->cga.vram[((nga->cga.memaddr << 1) & 0x1fff) + dat2 + 1]; /* each pixel is represented by one bit, so draw 16 pixels at a time */ /* crtc[1] is 40 column, so 40x16=640 pixels */ for (c = 0; c < 16; c++) { @@ -322,13 +322,13 @@ nga_poll(void *priv) /* 640x400x4 */ } else { /* lines 2,3,6,7,etc. */ - if (nga->cga.sc & 2) + if (nga->cga.scanline & 2) /* read two bytes at a time */ - dat = (nga->vram_64k[((nga->cga.ma << 1) & 0x7fff) + dat2] << 8) | nga->vram_64k[((nga->cga.ma << 1) & 0x7fff) + dat2 + 1]; + dat = (nga->vram_64k[((nga->cga.memaddr << 1) & 0x7fff) + dat2] << 8) | nga->vram_64k[((nga->cga.memaddr << 1) & 0x7fff) + dat2 + 1]; /* lines 0,1,4,5,etc. */ else /* read two bytes at a time */ - dat = (nga->cga.vram[((nga->cga.ma << 1) & 0x7fff) + dat2] << 8) | nga->cga.vram[((nga->cga.ma << 1) & 0x7fff) + dat2 + 1]; + dat = (nga->cga.vram[((nga->cga.memaddr << 1) & 0x7fff) + dat2] << 8) | nga->cga.vram[((nga->cga.memaddr << 1) & 0x7fff) + dat2 + 1]; /* each pixel is represented by two bits, so draw 8 pixels at a time */ /* crtc[1] is 80 column, so 80x8=640 pixels */ for (c = 0; c < 8; c++) { @@ -339,7 +339,7 @@ nga_poll(void *priv) } else { dat = 0; } - nga->cga.ma++; + nga->cga.memaddr++; } } } else { @@ -347,26 +347,26 @@ nga_poll(void *priv) /* nga specific */ cols[0] = ((nga->cga.cgamode & 0x12) == 0x12) ? 0 : (nga->cga.cgacol & 15) + 16; /* 80-col */ - if (nga->cga.cgamode & 1) { - hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[1] << 3) + 16) << 2, cols[0]); - hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[1] << 3) + 16) << 2, cols[0]); + if (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { + hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[CGA_CRTC_HDISP] << 3) + 16) << 2, cols[0]); + hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[CGA_CRTC_HDISP] << 3) + 16) << 2, cols[0]); } else { - hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[1] << 4) + 16) << 2, cols[0]); - hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[1] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, (nga->cga.displine << 1), ((nga->cga.crtc[CGA_CRTC_HDISP] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, (nga->cga.displine << 1) + 1, ((nga->cga.crtc[CGA_CRTC_HDISP] << 4) + 16) << 2, cols[0]); } } - if (nga->cga.cgamode & 1) + if (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) /* set screen width */ - x = (nga->cga.crtc[1] << 3) + 16; + x = (nga->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (nga->cga.crtc[1] << 4) + 16; + x = (nga->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; video_process_8(x, nga->cga.displine); - nga->cga.sc = oldsc; + nga->cga.scanline = scanline_old; /* vertical sync */ - if (nga->cga.vc == nga->cga.crtc[7] && !nga->cga.sc) + if (nga->cga.vc == nga->cga.crtc[CGA_CRTC_VSYNC] && !nga->cga.scanline) nga->cga.cgastat |= 8; nga->cga.displine++; if (nga->cga.displine >= 720) @@ -380,8 +380,8 @@ nga_poll(void *priv) nga->lineff ^= 1; /* text mode or 640x400x2 */ - if (nga->lineff && !((nga->cga.cgamode & 1) && (nga->cga.cgamode & 0x40))) { - nga->cga.ma = nga->cga.maback; + if (nga->lineff && !((nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) && (nga->cga.cgamode & 0x40))) { + nga->cga.memaddr = nga->cga.memaddr_backup; /* 640x400x4 */ } else { if (nga->cga.vsynctime) { @@ -390,49 +390,49 @@ nga_poll(void *priv) nga->cga.cgastat &= ~8; } /* cursor stop scanline */ - if (nga->cga.sc == (nga->cga.crtc[11] & 31) || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == ((nga->cga.crtc[11] & 31) >> 1))) { - nga->cga.con = 0; + if (nga->cga.scanline == (nga->cga.crtc[CGA_CRTC_CURSOR_END] & 31) || ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && nga->cga.scanline == ((nga->cga.crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + nga->cga.cursorvisible = 0; } /* interlaced and max scanline per char reached */ - if ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == (nga->cga.crtc[9] >> 1)) - nga->cga.maback = nga->cga.ma; + if ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && nga->cga.scanline == (nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) + nga->cga.memaddr_backup = nga->cga.memaddr; if (nga->cga.vadj) { - nga->cga.sc++; - nga->cga.sc &= 31; - nga->cga.ma = nga->cga.maback; + nga->cga.scanline++; + nga->cga.scanline &= 31; + nga->cga.memaddr = nga->cga.memaddr_backup; nga->cga.vadj--; if (!nga->cga.vadj) { nga->cga.cgadispon = 1; /* change start of displayed page (crtc 12-13) */ - nga->cga.ma = nga->cga.maback = (nga->cga.crtc[13] | (nga->cga.crtc[12] << 8)) & 0x7fff; - nga->cga.sc = 0; + nga->cga.memaddr = nga->cga.memaddr_backup = (nga->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (nga->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; + nga->cga.scanline = 0; } /* nga specific */ /* end of character line reached */ - } else if (nga->cga.sc == nga->cga.crtc[9] || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == (nga->cga.crtc[9] >> 1))) { - nga->cga.maback = nga->cga.ma; - nga->cga.sc = 0; + } else if (nga->cga.scanline == nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] || ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && nga->cga.scanline == (nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1))) { + nga->cga.memaddr_backup = nga->cga.memaddr; + nga->cga.scanline = 0; oldvc = nga->cga.vc; nga->cga.vc++; nga->cga.vc &= 127; /* lines of character displayed */ - if (nga->cga.vc == nga->cga.crtc[6]) + if (nga->cga.vc == nga->cga.crtc[CGA_CRTC_VDISP]) nga->cga.cgadispon = 0; /* total vertical lines */ - if (oldvc == nga->cga.crtc[4]) { + if (oldvc == nga->cga.crtc[CGA_CRTC_VTOTAL]) { nga->cga.vc = 0; /* adjust vertical lines */ - nga->cga.vadj = nga->cga.crtc[5]; + nga->cga.vadj = nga->cga.crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!nga->cga.vadj) { nga->cga.cgadispon = 1; /* change start of displayed page (crtc 12-13) */ - nga->cga.ma = nga->cga.maback = (nga->cga.crtc[13] | (nga->cga.crtc[12] << 8)) & 0x7fff; + nga->cga.memaddr = nga->cga.memaddr_backup = (nga->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (nga->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; } /* cursor start */ - switch (nga->cga.crtc[10] & 0x60) { + switch (nga->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) { case 0x20: nga->cga.cursoron = 0; break; @@ -445,18 +445,18 @@ nga_poll(void *priv) } } /* vertical line position */ - if (nga->cga.vc == nga->cga.crtc[7]) { + if (nga->cga.vc == nga->cga.crtc[CGA_CRTC_VSYNC]) { nga->cga.cgadispon = 0; nga->cga.displine = 0; /* nga specific */ nga->cga.vsynctime = 16; /* vsync pos */ - if (nga->cga.crtc[7]) { - if (nga->cga.cgamode & 1) + if (nga->cga.crtc[CGA_CRTC_VSYNC]) { + if (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) /* set screen width */ - x = (nga->cga.crtc[1] << 3) + 16; + x = (nga->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (nga->cga.crtc[1] << 4) + 16; + x = (nga->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; nga->cga.lastline++; xs_temp = x; @@ -471,7 +471,7 @@ nga_poll(void *priv) if (!enable_overscan) xs_temp -= 16; - if ((nga->cga.cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + if ((nga->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { xsize = xs_temp; ysize = ys_temp; set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); @@ -493,14 +493,14 @@ nga_poll(void *priv) video_res_x = xsize; video_res_y = ysize; /* 80-col */ - if ((nga->cga.cgamode & 1) && !(nga->cga.cgamode & 0x40)) { + if ((nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES) && !(nga->cga.cgamode & 0x40)) { video_res_x /= 8; - video_res_y /= (nga->cga.crtc[9] + 1) * 2; + video_res_y /= (nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * 2; video_bpp = 0; /* 40-col */ - } else if (!(nga->cga.cgamode & 2)) { + } else if (!(nga->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; - video_res_y /= (nga->cga.crtc[9] + 1) * 2; + video_res_y /= (nga->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * 2; video_bpp = 0; } else if (nga->cga.cgamode & 0x40) { video_res_x /= 8; @@ -514,23 +514,23 @@ nga_poll(void *priv) nga->cga.oddeven ^= 1; } } else { - nga->cga.sc++; - nga->cga.sc &= 31; - nga->cga.ma = nga->cga.maback; + nga->cga.scanline++; + nga->cga.scanline &= 31; + nga->cga.memaddr = nga->cga.memaddr_backup; } if (nga->cga.cgadispon) nga->cga.cgastat &= ~1; /* enable cursor if its scanline was reached */ - if (nga->cga.sc == (nga->cga.crtc[10] & 31) || ((nga->cga.crtc[8] & 3) == 3 && nga->cga.sc == ((nga->cga.crtc[10] & 31) >> 1))) - nga->cga.con = 1; + if (nga->cga.scanline == (nga->cga.crtc[CGA_CRTC_CURSOR_START] & 31) || ((nga->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && nga->cga.scanline == ((nga->cga.crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + nga->cga.cursorvisible = 1; } /* 80-columns */ - if (nga->cga.cgadispon && (nga->cga.cgamode & 1)) { + if (nga->cga.cgadispon && (nga->cga.cgamode & CGA_MODE_FLAG_HIGHRES)) { /* for each character per line */ - for (x = 0; x < (nga->cga.crtc[1] << 1); x++) - nga->cga.charbuffer[x] = nga->cga.vram[(((nga->cga.ma << 1) + x) & 0x3fff) + nga->base]; + for (x = 0; x < (nga->cga.crtc[CGA_CRTC_HDISP] << 1); x++) + nga->cga.charbuffer[x] = nga->cga.vram[(((nga->cga.memaddr << 1) + x) & 0x3fff) + nga->base]; } } } diff --git a/src/video/vid_ogc.c b/src/video/vid_cga_olivetti.c similarity index 75% rename from src/video/vid_ogc.c rename to src/video/vid_cga_olivetti.c index 162cb9073..8be40ee2e 100644 --- a/src/video/vid_ogc.c +++ b/src/video/vid_cga_olivetti.c @@ -65,12 +65,12 @@ ogc_recalctimings(ogc_t *ogc) double _dispofftime; double disptime; - if (ogc->cga.cgamode & 1) { - disptime = ogc->cga.crtc[0] + 1; - _dispontime = ogc->cga.crtc[1]; + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { + disptime = ogc->cga.crtc[CGA_CRTC_HTOTAL] + 1; + _dispontime = ogc->cga.crtc[CGA_CRTC_HDISP]; } else { - disptime = (ogc->cga.crtc[0] + 1) << 1; - _dispontime = ogc->cga.crtc[1] << 1; + disptime = (ogc->cga.crtc[CGA_CRTC_HTOTAL] + 1) << 1; + _dispontime = ogc->cga.crtc[CGA_CRTC_HDISP] << 1; } _dispofftime = disptime - _dispontime; @@ -201,7 +201,7 @@ void ogc_poll(void *priv) { ogc_t *ogc = (ogc_t *) priv; - uint16_t ca = (ogc->cga.crtc[15] | (ogc->cga.crtc[14] << 8)) & 0x3fff; + uint16_t cursoraddr = (ogc->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (ogc->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; int drawcursor; int x; int c; @@ -213,14 +213,14 @@ ogc_poll(void *priv) uint16_t dat; uint16_t dat2; int cols[4]; - int oldsc; + int scanline_old; int blink = 0; int underline = 0; - // composito colore appare blu scuro + // Composite color appears dark blue /* graphic mode and not mode 40h */ - if (!(ogc->ctrl_3de & 0x1 || !(ogc->cga.cgamode & 2))) { + if (!(ogc->ctrl_3de & 0x1 || !(ogc->cga.cgamode & CGA_MODE_FLAG_GRAPHICS))) { /* standard cga mode */ cga_poll(&ogc->cga); return; @@ -230,9 +230,9 @@ ogc_poll(void *priv) timer_advance_u64(&ogc->cga.timer, ogc->cga.dispofftime); ogc->cga.cgastat |= 1; ogc->cga.linepos = 1; - oldsc = ogc->cga.sc; - if ((ogc->cga.crtc[8] & 3) == 3) - ogc->cga.sc = ((ogc->cga.sc << 1) + ogc->cga.oddeven) & 7; + scanline_old = ogc->cga.scanline; + if ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3) + ogc->cga.scanline = ((ogc->cga.scanline << 1) + ogc->cga.oddeven) & 7; if (ogc->cga.cgadispon) { if (ogc->cga.displine < ogc->cga.firstline) { ogc->cga.firstline = ogc->cga.displine; @@ -240,11 +240,11 @@ ogc_poll(void *priv) } ogc->cga.lastline = ogc->cga.displine; /* 80-col */ - if (ogc->cga.cgamode & 1) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { /* for each text column */ - for (x = 0; x < ogc->cga.crtc[1]; x++) { + for (x = 0; x < ogc->cga.crtc[CGA_CRTC_HDISP]; x++) { /* video output enabled */ - if (ogc->cga.cgamode & 8) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { /* character */ chr = ogc->cga.charbuffer[x << 1]; /* text attributes */ @@ -252,7 +252,7 @@ ogc_poll(void *priv) } else chr = attr = 0; /* check if cursor has to be drawn */ - drawcursor = ((ogc->cga.ma == ca) && ogc->cga.con && ogc->cga.cursoron); + drawcursor = ((ogc->cga.memaddr == cursoraddr) && ogc->cga.cursorvisible && ogc->cga.cursoron); /* check if character underline mode should be set */ underline = ((ogc->ctrl_3de & 0x40) && (attr & 0x1) && !(attr & 0x6)); if (underline) { @@ -263,7 +263,7 @@ ogc_poll(void *priv) /* set foreground */ cols[1] = (attr & 15) + 16; /* blink active */ - if (ogc->cga.cgamode & 0x20) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; /* attribute 7 active and not cursor */ if ((ogc->cga.cgablink & 8) && (attr & 0x80) && !ogc->cga.drawcursor) { @@ -277,31 +277,31 @@ ogc_poll(void *priv) blink = (attr & 0x80) * 8 + 7 + 16; } /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (ogc->cga.sc == 7)) { + if (underline && (ogc->cga.scanline == 7)) { /* for each pixel in character width */ for (c = 0; c < 8; c++) buffer32->line[ogc->cga.displine][(x << 3) + c + 8] = mdaattr[attr][blink][1]; } else if (drawcursor) { for (c = 0; c < 8; c++) - buffer32->line[ogc->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((ogc->cga.sc & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + buffer32->line[ogc->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((ogc->cga.scanline & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - buffer32->line[ogc->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((ogc->cga.sc & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[ogc->cga.displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((ogc->cga.scanline & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0]; } - ogc->cga.ma++; + ogc->cga.memaddr++; } } /* 40-col */ - else if (!(ogc->cga.cgamode & 2)) { - for (x = 0; x < ogc->cga.crtc[1]; x++) { - if (ogc->cga.cgamode & 8) { - chr = ogc->cga.vram[((ogc->cga.ma << 1) & 0x3fff) + ogc->base]; - attr = ogc->cga.vram[(((ogc->cga.ma << 1) + 1) & 0x3fff) + ogc->base]; + else if (!(ogc->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { + for (x = 0; x < ogc->cga.crtc[CGA_CRTC_HDISP]; x++) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { + chr = ogc->cga.vram[((ogc->cga.memaddr << 1) & 0x3fff) + ogc->base]; + attr = ogc->cga.vram[(((ogc->cga.memaddr << 1) + 1) & 0x3fff) + ogc->base]; } else { chr = attr = 0; } - drawcursor = ((ogc->cga.ma == ca) && ogc->cga.con && ogc->cga.cursoron); + drawcursor = ((ogc->cga.memaddr == cursoraddr) && ogc->cga.cursorvisible && ogc->cga.cursoron); /* check if character underline mode should be set */ underline = ((ogc->ctrl_3de & 0x40) && (attr & 0x1) && !(attr & 0x6)); if (underline) { @@ -312,7 +312,7 @@ ogc_poll(void *priv) /* set foreground */ cols[1] = (attr & 15) + 16; /* blink active */ - if (ogc->cga.cgamode & 0x20) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_BLINK) { cols[0] = ((attr >> 4) & 7) + 16; if ((ogc->cga.cgablink & 8) && (attr & 0x80) && !ogc->cga.drawcursor) { /* set blinking */ @@ -326,40 +326,40 @@ ogc_poll(void *priv) } /* character underline active and 7th row of pixels in character height being drawn */ - if (underline && (ogc->cga.sc == 7)) { + if (underline && (ogc->cga.scanline == 7)) { /* for each pixel in character width */ for (c = 0; c < 8; c++) buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 1 + 8] = mdaattr[attr][blink][1]; } else if (drawcursor) { for (c = 0; c < 8; c++) - buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((ogc->cga.sc & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((ogc->cga.scanline & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; } else { for (c = 0; c < 8; c++) - buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((ogc->cga.sc & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 8] = buffer32->line[ogc->cga.displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((ogc->cga.scanline & 7) << 1) | ogc->lineff] & (1 << (c ^ 7))) ? 1 : 0]; } - ogc->cga.ma++; + ogc->cga.memaddr++; } } else { /* 640x400 mode */ if (ogc->ctrl_3de & 1) { - dat2 = ((ogc->cga.sc & 1) * 0x4000) | (ogc->lineff * 0x2000); + dat2 = ((ogc->cga.scanline & 1) * 0x4000) | (ogc->lineff * 0x2000); cols[0] = 0; cols[1] = 15 + 16; } else { - dat2 = (ogc->cga.sc & 1) * 0x2000; + dat2 = (ogc->cga.scanline & 1) * 0x2000; cols[0] = 0; cols[1] = (ogc->cga.cgacol & 15) + 16; } - for (x = 0; x < ogc->cga.crtc[1]; x++) { + for (x = 0; x < ogc->cga.crtc[CGA_CRTC_HDISP]; x++) { /* video out */ - if (ogc->cga.cgamode & 8) { - dat = (ogc->cga.vram[((ogc->cga.ma << 1) & 0x1fff) + dat2] << 8) | ogc->cga.vram[((ogc->cga.ma << 1) & 0x1fff) + dat2 + 1]; + if (ogc->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) { + dat = (ogc->cga.vram[((ogc->cga.memaddr << 1) & 0x1fff) + dat2] << 8) | ogc->cga.vram[((ogc->cga.memaddr << 1) & 0x1fff) + dat2 + 1]; } else { dat = 0; } - ogc->cga.ma++; + ogc->cga.memaddr++; for (c = 0; c < 16; c++) { buffer32->line[ogc->cga.displine][(x << 4) + c + 8] = cols[dat >> 15]; @@ -370,22 +370,22 @@ ogc_poll(void *priv) } else { /* ogc specific */ cols[0] = ((ogc->cga.cgamode & 0x12) == 0x12) ? 0 : (ogc->cga.cgacol & 15) + 16; - if (ogc->cga.cgamode & 1) - hline(buffer32, 0, ogc->cga.displine, ((ogc->cga.crtc[1] << 3) + 16) << 2, cols[0]); + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) + hline(buffer32, 0, ogc->cga.displine, ((ogc->cga.crtc[CGA_CRTC_HDISP] << 3) + 16) << 2, cols[0]); else - hline(buffer32, 0, ogc->cga.displine, ((ogc->cga.crtc[1] << 4) + 16) << 2, cols[0]); + hline(buffer32, 0, ogc->cga.displine, ((ogc->cga.crtc[CGA_CRTC_HDISP] << 4) + 16) << 2, cols[0]); } /* 80 columns */ - if (ogc->cga.cgamode & 1) - x = (ogc->cga.crtc[1] << 3) + 16; + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) + x = (ogc->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (ogc->cga.crtc[1] << 4) + 16; + x = (ogc->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; video_process_8(x, ogc->cga.displine); - ogc->cga.sc = oldsc; - if (ogc->cga.vc == ogc->cga.crtc[7] && !ogc->cga.sc) + ogc->cga.scanline = scanline_old; + if (ogc->cga.vc == ogc->cga.crtc[CGA_CRTC_VSYNC] && !ogc->cga.scanline) ogc->cga.cgastat |= 8; ogc->cga.displine++; if (ogc->cga.displine >= 720) @@ -398,47 +398,47 @@ ogc_poll(void *priv) /* ogc specific */ ogc->lineff ^= 1; if (ogc->lineff) { - ogc->cga.ma = ogc->cga.maback; + ogc->cga.memaddr = ogc->cga.memaddr_backup; } else { if (ogc->cga.vsynctime) { ogc->cga.vsynctime--; if (!ogc->cga.vsynctime) ogc->cga.cgastat &= ~8; } - if (ogc->cga.sc == (ogc->cga.crtc[11] & 31) || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == ((ogc->cga.crtc[11] & 31) >> 1))) { - ogc->cga.con = 0; + if (ogc->cga.scanline == (ogc->cga.crtc[CGA_CRTC_CURSOR_END] & 31) || ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && ogc->cga.scanline == ((ogc->cga.crtc[CGA_CRTC_CURSOR_END] & 31) >> 1))) { + ogc->cga.cursorvisible = 0; } - if ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == (ogc->cga.crtc[9] >> 1)) - ogc->cga.maback = ogc->cga.ma; + if ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && ogc->cga.scanline == (ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1)) + ogc->cga.memaddr_backup = ogc->cga.memaddr; if (ogc->cga.vadj) { - ogc->cga.sc++; - ogc->cga.sc &= 31; - ogc->cga.ma = ogc->cga.maback; + ogc->cga.scanline++; + ogc->cga.scanline &= 31; + ogc->cga.memaddr = ogc->cga.memaddr_backup; ogc->cga.vadj--; if (!ogc->cga.vadj) { ogc->cga.cgadispon = 1; - ogc->cga.ma = ogc->cga.maback = (ogc->cga.crtc[13] | (ogc->cga.crtc[12] << 8)) & 0x3fff; - ogc->cga.sc = 0; + ogc->cga.memaddr = ogc->cga.memaddr_backup = (ogc->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (ogc->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + ogc->cga.scanline = 0; } - // potrebbe dare problemi con composito - } else if (ogc->cga.sc == ogc->cga.crtc[9] || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == (ogc->cga.crtc[9] >> 1))) { - ogc->cga.maback = ogc->cga.ma; - ogc->cga.sc = 0; + // may cause problems with composite + } else if (ogc->cga.scanline == ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] || ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && ogc->cga.scanline == (ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] >> 1))) { + ogc->cga.memaddr_backup = ogc->cga.memaddr; + ogc->cga.scanline = 0; oldvc = ogc->cga.vc; ogc->cga.vc++; ogc->cga.vc &= 127; - if (ogc->cga.vc == ogc->cga.crtc[6]) + if (ogc->cga.vc == ogc->cga.crtc[CGA_CRTC_VDISP]) ogc->cga.cgadispon = 0; - if (oldvc == ogc->cga.crtc[4]) { + if (oldvc == ogc->cga.crtc[CGA_CRTC_VTOTAL]) { ogc->cga.vc = 0; - ogc->cga.vadj = ogc->cga.crtc[5]; + ogc->cga.vadj = ogc->cga.crtc[CGA_CRTC_VTOTAL_ADJUST]; if (!ogc->cga.vadj) { ogc->cga.cgadispon = 1; - ogc->cga.ma = ogc->cga.maback = (ogc->cga.crtc[13] | (ogc->cga.crtc[12] << 8)) & 0x3fff; + ogc->cga.memaddr = ogc->cga.memaddr_backup = (ogc->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (ogc->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; } - switch (ogc->cga.crtc[10] & 0x60) { + switch (ogc->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) { case 0x20: ogc->cga.cursoron = 0; break; @@ -450,16 +450,16 @@ ogc_poll(void *priv) break; } } - if (ogc->cga.vc == ogc->cga.crtc[7]) { + if (ogc->cga.vc == ogc->cga.crtc[CGA_CRTC_VSYNC]) { ogc->cga.cgadispon = 0; ogc->cga.displine = 0; /* ogc specific */ - ogc->cga.vsynctime = (ogc->cga.crtc[3] >> 4) + 1; - if (ogc->cga.crtc[7]) { - if (ogc->cga.cgamode & 1) - x = (ogc->cga.crtc[1] << 3) + 16; + ogc->cga.vsynctime = (ogc->cga.crtc[CGA_CRTC_HSYNC_WIDTH] >> 4) + 1; + if (ogc->cga.crtc[CGA_CRTC_VSYNC]) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) + x = (ogc->cga.crtc[CGA_CRTC_HDISP] << 3) + 16; else - x = (ogc->cga.crtc[1] << 4) + 16; + x = (ogc->cga.crtc[CGA_CRTC_HDISP] << 4) + 16; ogc->cga.lastline++; xs_temp = x; @@ -474,7 +474,7 @@ ogc_poll(void *priv) if (!enable_overscan) xs_temp -= 16; - if ((ogc->cga.cgamode & 8) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { + if ((ogc->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get())) { xsize = xs_temp; ysize = ys_temp; set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); @@ -496,14 +496,14 @@ ogc_poll(void *priv) video_res_x = xsize; video_res_y = ysize; /* 80-col */ - if (ogc->cga.cgamode & 1) { + if (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES) { video_res_x /= 8; - video_res_y /= (ogc->cga.crtc[9] + 1) * 2; + video_res_y /= (ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * 2; video_bpp = 0; /* 40-col */ - } else if (!(ogc->cga.cgamode & 2)) { + } else if (!(ogc->cga.cgamode & CGA_MODE_FLAG_GRAPHICS)) { video_res_x /= 16; - video_res_y /= (ogc->cga.crtc[9] + 1) * 2; + video_res_y /= (ogc->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * 2; video_bpp = 0; } else if (!(ogc->ctrl_3de & 1)) { video_res_y /= 2; @@ -516,21 +516,21 @@ ogc_poll(void *priv) ogc->cga.oddeven ^= 1; } } else { - ogc->cga.sc++; - ogc->cga.sc &= 31; - ogc->cga.ma = ogc->cga.maback; + ogc->cga.scanline++; + ogc->cga.scanline &= 31; + ogc->cga.memaddr = ogc->cga.memaddr_backup; } if (ogc->cga.cgadispon) ogc->cga.cgastat &= ~1; - if (ogc->cga.sc == (ogc->cga.crtc[10] & 31) || ((ogc->cga.crtc[8] & 3) == 3 && ogc->cga.sc == ((ogc->cga.crtc[10] & 31) >> 1))) - ogc->cga.con = 1; + if (ogc->cga.scanline == (ogc->cga.crtc[CGA_CRTC_CURSOR_START] & 31) || ((ogc->cga.crtc[CGA_CRTC_INTERLACE] & 3) == 3 && ogc->cga.scanline == ((ogc->cga.crtc[CGA_CRTC_CURSOR_START] & 31) >> 1))) + ogc->cga.cursorvisible = 1; } /* 80-columns */ - if (ogc->cga.cgadispon && (ogc->cga.cgamode & 1)) { - for (x = 0; x < (ogc->cga.crtc[1] << 1); x++) - ogc->cga.charbuffer[x] = ogc->cga.vram[(((ogc->cga.ma << 1) + x) & 0x3fff) + ogc->base]; + if (ogc->cga.cgadispon && (ogc->cga.cgamode & CGA_MODE_FLAG_HIGHRES)) { + for (x = 0; x < (ogc->cga.crtc[CGA_CRTC_HDISP] << 1); x++) + ogc->cga.charbuffer[x] = ogc->cga.vram[(((ogc->cga.memaddr << 1) + x) & 0x3fff) + ogc->base]; } } } diff --git a/src/machine/m_xt_t1000_vid.c b/src/video/vid_cga_toshiba_t1000.c similarity index 88% rename from src/machine/m_xt_t1000_vid.c rename to src/video/vid_cga_toshiba_t1000.c index efad869e1..2fd382272 100644 --- a/src/machine/m_xt_t1000_vid.c +++ b/src/video/vid_cga_toshiba_t1000.c @@ -245,25 +245,25 @@ t1000_text_row80(t1000_t *t1000) int bold; int blink; uint16_t addr; - uint8_t sc; - uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; - uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff; + uint8_t scanline; + uint16_t memaddr = (t1000->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + uint16_t cursoraddr = (t1000->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; - sc = (t1000->displine) & 7; - addr = ((ma & ~1) + (t1000->displine >> 3) * 80) * 2; - ma += (t1000->displine >> 3) * 80; + scanline = (t1000->displine) & 7; + addr = ((memaddr & ~1) + (t1000->displine >> 3) * 80) * 2; + memaddr += (t1000->displine >> 3) * 80; - if ((t1000->cga.crtc[10] & 0x60) == 0x20) { + if ((t1000->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) && ((t1000->cga.crtc[11] & 0x0F) >= sc); + cursorline = ((t1000->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) <= scanline) && ((t1000->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) >= scanline); } for (uint8_t x = 0; x < 80; x++) { chr = t1000->vram[(addr + 2 * x) & 0x3FFF]; attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && (t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16)); + drawcursor = ((memaddr == cursoraddr) && cursorline && (t1000->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (t1000->cga.cgablink & 16)); - blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (t1000->video_options & 1) bold = boldcols[attr] ? chr : chr + 256; @@ -272,7 +272,7 @@ t1000_text_row80(t1000_t *t1000) if (t1000->video_options & 2) bold += 512; - if (t1000->cga.cgamode & 0x20) /* Blink */ + if (t1000->cga.cgamode & CGA_MODE_FLAG_BLINK) /* Blink */ { cols[1] = blinkcols[attr][1]; cols[0] = blinkcols[attr][0]; @@ -284,13 +284,13 @@ t1000_text_row80(t1000_t *t1000) } if (drawcursor) { for (uint8_t c = 0; c < 8; c++) { - (buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); + (buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][scanline] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); } } else { for (uint8_t c = 0; c < 8; c++) - (buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + (buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][scanline] & (1 << (c ^ 7))) ? 1 : 0]; } - ++ma; + ++memaddr; } } @@ -306,25 +306,25 @@ t1000_text_row40(t1000_t *t1000) int bold; int blink; uint16_t addr; - uint8_t sc; - uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; - uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff; + uint8_t scanline; + uint16_t memaddr = (t1000->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + uint16_t cursoraddr = (t1000->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; - sc = (t1000->displine) & 7; - addr = ((ma & ~1) + (t1000->displine >> 3) * 40) * 2; - ma += (t1000->displine >> 3) * 40; + scanline = (t1000->displine) & 7; + addr = ((memaddr & ~1) + (t1000->displine >> 3) * 40) * 2; + memaddr += (t1000->displine >> 3) * 40; - if ((t1000->cga.crtc[10] & 0x60) == 0x20) { + if ((t1000->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) && ((t1000->cga.crtc[11] & 0x0F) >= sc); + cursorline = ((t1000->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) <= scanline) && ((t1000->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) >= scanline); } for (uint8_t x = 0; x < 40; x++) { chr = t1000->vram[(addr + 2 * x) & 0x3FFF]; attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && (t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16)); + drawcursor = ((memaddr == cursoraddr) && cursorline && (t1000->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (t1000->cga.cgablink & 16)); - blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (t1000->video_options & 1) bold = boldcols[attr] ? chr : chr + 256; @@ -333,7 +333,7 @@ t1000_text_row40(t1000_t *t1000) if (t1000->video_options & 2) bold += 512; - if (t1000->cga.cgamode & 0x20) /* Blink */ + if (t1000->cga.cgamode & CGA_MODE_FLAG_BLINK) /* Blink */ { cols[1] = blinkcols[attr][1]; cols[0] = blinkcols[attr][0]; @@ -345,14 +345,14 @@ t1000_text_row40(t1000_t *t1000) } if (drawcursor) { for (uint8_t c = 0; c < 8; c++) { - (buffer32->line[t1000->displine])[(x << 4) + c * 2] = (buffer32->line[t1000->displine])[(x << 4) + c * 2 + 1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); + (buffer32->line[t1000->displine])[(x << 4) + c * 2] = (buffer32->line[t1000->displine])[(x << 4) + c * 2 + 1] = cols[(fontdat[bold][scanline] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); } } else { for (uint8_t c = 0; c < 8; c++) { - (buffer32->line[t1000->displine])[(x << 4) + c * 2] = (buffer32->line[t1000->displine])[(x << 4) + c * 2 + 1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + (buffer32->line[t1000->displine])[(x << 4) + c * 2] = (buffer32->line[t1000->displine])[(x << 4) + c * 2 + 1] = cols[(fontdat[bold][scanline] & (1 << (c ^ 7))) ? 1 : 0]; } } - ++ma; + ++memaddr; } } @@ -366,9 +366,9 @@ t1000_cgaline6(t1000_t *t1000) uint32_t fg = (t1000->cga.cgacol & 0x0F) ? blue : grey; uint32_t bg = grey; - uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; + uint16_t memaddr = (t1000->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; - addr = ((t1000->displine) & 1) * 0x2000 + (t1000->displine >> 1) * 80 + ((ma & ~1) << 1); + addr = ((t1000->displine) & 1) * 0x2000 + (t1000->displine >> 1) * 80 + ((memaddr & ~1) << 1); for (uint8_t x = 0; x < 80; x++) { dat = t1000->vram[addr & 0x3FFF]; @@ -376,7 +376,7 @@ t1000_cgaline6(t1000_t *t1000) for (uint8_t c = 0; c < 8; c++) { ink = (dat & 0x80) ? fg : bg; - if (!(t1000->cga.cgamode & 8)) + if (!(t1000->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE)) ink = grey; (buffer32->line[t1000->displine])[x * 8 + c] = ink; dat = dat << 1; @@ -395,8 +395,8 @@ t1000_cgaline4(t1000_t *t1000) uint32_t ink1; uint16_t addr; - uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; - addr = ((t1000->displine) & 1) * 0x2000 + (t1000->displine >> 1) * 80 + ((ma & ~1) << 1); + uint16_t memaddr = (t1000->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t1000->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + addr = ((t1000->displine) & 1) * 0x2000 + (t1000->displine >> 1) * 80 + ((memaddr & ~1) << 1); for (uint8_t x = 0; x < 80; x++) { dat = t1000->vram[addr & 0x3FFF]; @@ -404,7 +404,7 @@ t1000_cgaline4(t1000_t *t1000) for (uint8_t c = 0; c < 4; c++) { pattern = (dat & 0xC0) >> 6; - if (!(t1000->cga.cgamode & 8)) + if (!(t1000->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE)) pattern = 0; switch (pattern & 3) { @@ -479,7 +479,7 @@ t1000_poll(void *priv) /* Graphics */ if (t1000->cga.cgamode & 0x02) { - if (t1000->cga.cgamode & 0x10) + if (t1000->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) t1000_cgaline6(t1000); else t1000_cgaline4(t1000); @@ -532,7 +532,7 @@ t1000_poll(void *priv) video_res_y = T1000_YSIZE; if (t1000->cga.cgamode & 0x02) { - if (t1000->cga.cgamode & 0x10) + if (t1000->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) video_bpp = 1; else video_bpp = 2; diff --git a/src/machine/m_at_t3100e_vid.c b/src/video/vid_cga_toshiba_t3100e.c similarity index 84% rename from src/machine/m_at_t3100e_vid.c rename to src/video/vid_cga_toshiba_t3100e.c index c827a05e5..e3eb673c8 100644 --- a/src/machine/m_at_t3100e_vid.c +++ b/src/video/vid_cga_toshiba_t3100e.c @@ -169,8 +169,8 @@ t3100e_out(uint16_t addr, uint8_t val, void *priv) t3100e_recalctimings(t3100e); return; - case 0x3D8: /* CGA control register */ - case 0x3D9: /* CGA colour register */ + case CGA_REGISTER_MODE_CONTROL: /* CGA control register */ + case CGA_REGISTER_COLOR_SELECT: /* CGA colour register */ cga_out(addr, val, &t3100e->cga); return; @@ -254,25 +254,25 @@ t3100e_text_row80(t3100e_t *t3100e) int bold; int blink; uint16_t addr; - uint8_t sc; - uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; - uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff; + uint8_t scanline; + uint16_t memaddr = (t3100e->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; + uint16_t cursoraddr = (t3100e->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x7fff; - sc = (t3100e->displine) & 15; - addr = ((ma & ~1) + (t3100e->displine >> 4) * 80) * 2; - ma += (t3100e->displine >> 4) * 80; + scanline = (t3100e->displine) & 15; + addr = ((memaddr & ~1) + (t3100e->displine >> 4) * 80) * 2; + memaddr += (t3100e->displine >> 4) * 80; - if ((t3100e->cga.crtc[10] & 0x60) == 0x20) { + if ((t3100e->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((t3100e->cga.crtc[10] & 0x0F) * 2 <= sc) && ((t3100e->cga.crtc[11] & 0x0F) * 2 >= sc); + cursorline = ((t3100e->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) * 2 <= scanline) && ((t3100e->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) * 2 >= scanline); } for (uint8_t x = 0; x < 80; x++) { chr = t3100e->vram[(addr + 2 * x) & 0x7FFF]; attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF]; - drawcursor = ((ma == ca) && cursorline && (t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16)); + drawcursor = ((memaddr == cursoraddr) && cursorline && (t3100e->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (t3100e->cga.cgablink & 16)); - blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (t3100e->video_options & 4) bold = boldcols[attr] ? chr + 256 : chr; @@ -280,7 +280,7 @@ t3100e_text_row80(t3100e_t *t3100e) bold = boldcols[attr] ? chr : chr + 256; bold += 512 * (t3100e->video_options & 3); - if (t3100e->cga.cgamode & 0x20) /* Blink */ + if (t3100e->cga.cgamode & CGA_MODE_FLAG_BLINK) /* Blink */ { cols[1] = blinkcols[attr][1]; cols[0] = blinkcols[attr][0]; @@ -292,13 +292,13 @@ t3100e_text_row80(t3100e_t *t3100e) } if (drawcursor) { for (uint8_t c = 0; c < 8; c++) { - (buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + (buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][scanline] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); } } else { for (uint8_t c = 0; c < 8; c++) - (buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + (buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][scanline] & (1 << (c ^ 7))) ? 1 : 0]; } - ++ma; + ++memaddr; } } @@ -315,25 +315,25 @@ t3100e_text_row40(t3100e_t *t3100e) int bold; int blink; uint16_t addr; - uint8_t sc; - uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; - uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff; + uint8_t scanline; + uint16_t memaddr = (t3100e->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; + uint16_t cursoraddr = (t3100e->cga.crtc[CGA_CRTC_CURSOR_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x7fff; - sc = (t3100e->displine) & 15; - addr = ((ma & ~1) + (t3100e->displine >> 4) * 40) * 2; - ma += (t3100e->displine >> 4) * 40; + scanline = (t3100e->displine) & 15; + addr = ((memaddr & ~1) + (t3100e->displine >> 4) * 40) * 2; + memaddr += (t3100e->displine >> 4) * 40; - if ((t3100e->cga.crtc[10] & 0x60) == 0x20) { + if ((t3100e->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((t3100e->cga.crtc[10] & 0x0F) * 2 <= sc) && ((t3100e->cga.crtc[11] & 0x0F) * 2 >= sc); + cursorline = ((t3100e->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) * 2 <= scanline) && ((t3100e->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) * 2 >= scanline); } for (uint8_t x = 0; x < 40; x++) { chr = t3100e->vram[(addr + 2 * x) & 0x7FFF]; attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF]; - drawcursor = ((ma == ca) && cursorline && (t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16)); + drawcursor = ((memaddr == cursoraddr) && cursorline && (t3100e->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (t3100e->cga.cgablink & 16)); - blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (t3100e->video_options & 4) bold = boldcols[attr] ? chr + 256 : chr; @@ -341,7 +341,7 @@ t3100e_text_row40(t3100e_t *t3100e) bold = boldcols[attr] ? chr : chr + 256; bold += 512 * (t3100e->video_options & 3); - if (t3100e->cga.cgamode & 0x20) /* Blink */ + if (t3100e->cga.cgamode & CGA_MODE_FLAG_BLINK) /* Blink */ { cols[1] = blinkcols[attr][1]; cols[0] = blinkcols[attr][0]; @@ -353,14 +353,14 @@ t3100e_text_row40(t3100e_t *t3100e) } if (drawcursor) { for (c = 0; c < 8; c++) { - (buffer32->line[t3100e->displine])[(x << 4) + c * 2] = (buffer32->line[t3100e->displine])[(x << 4) + c * 2 + 1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + (buffer32->line[t3100e->displine])[(x << 4) + c * 2] = (buffer32->line[t3100e->displine])[(x << 4) + c * 2 + 1] = cols[(fontdatm[bold][scanline] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); } } else { for (c = 0; c < 8; c++) { - (buffer32->line[t3100e->displine])[(x << 4) + c * 2] = (buffer32->line[t3100e->displine])[(x << 4) + c * 2 + 1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + (buffer32->line[t3100e->displine])[(x << 4) + c * 2] = (buffer32->line[t3100e->displine])[(x << 4) + c * 2 + 1] = cols[(fontdatm[bold][scanline] & (1 << (c ^ 7))) ? 1 : 0]; } } - ++ma; + ++memaddr; } } @@ -374,13 +374,13 @@ t3100e_cgaline6(t3100e_t *t3100e) uint32_t fg = (t3100e->cga.cgacol & 0x0F) ? amber : black; uint32_t bg = black; - uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; + uint16_t memaddr = (t3100e->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; - if (t3100e->cga.crtc[9] == 3) /* 640*400 */ + if (t3100e->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] == 3) /* 640*400 */ { - addr = ((t3100e->displine) & 1) * 0x2000 + ((t3100e->displine >> 1) & 1) * 0x4000 + (t3100e->displine >> 2) * 80 + ((ma & ~1) << 1); + addr = ((t3100e->displine) & 1) * 0x2000 + ((t3100e->displine >> 1) & 1) * 0x4000 + (t3100e->displine >> 2) * 80 + ((memaddr & ~1) << 1); } else { - addr = ((t3100e->displine >> 1) & 1) * 0x2000 + (t3100e->displine >> 2) * 80 + ((ma & ~1) << 1); + addr = ((t3100e->displine >> 1) & 1) * 0x2000 + (t3100e->displine >> 2) * 80 + ((memaddr & ~1) << 1); } for (uint8_t x = 0; x < 80; x++) { dat = t3100e->vram[addr & 0x7FFF]; @@ -388,7 +388,7 @@ t3100e_cgaline6(t3100e_t *t3100e) for (uint8_t c = 0; c < 8; c++) { ink = (dat & 0x80) ? fg : bg; - if (!(t3100e->cga.cgamode & 8)) + if (!(t3100e->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE)) ink = black; (buffer32->line[t3100e->displine])[x * 8 + c] = ink; dat = dat << 1; @@ -407,13 +407,13 @@ t3100e_cgaline4(t3100e_t *t3100e) uint32_t ink1 = 0; uint16_t addr; - uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; - if (t3100e->cga.crtc[9] == 3) /* 320*400 undocumented */ + uint16_t memaddr = (t3100e->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (t3100e->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x7fff; + if (t3100e->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] == 3) /* 320*400 undocumented */ { - addr = ((t3100e->displine) & 1) * 0x2000 + ((t3100e->displine >> 1) & 1) * 0x4000 + (t3100e->displine >> 2) * 80 + ((ma & ~1) << 1); + addr = ((t3100e->displine) & 1) * 0x2000 + ((t3100e->displine >> 1) & 1) * 0x4000 + (t3100e->displine >> 2) * 80 + ((memaddr & ~1) << 1); } else /* 320*200 */ { - addr = ((t3100e->displine >> 1) & 1) * 0x2000 + (t3100e->displine >> 2) * 80 + ((ma & ~1) << 1); + addr = ((t3100e->displine >> 1) & 1) * 0x2000 + (t3100e->displine >> 2) * 80 + ((memaddr & ~1) << 1); } for (uint8_t x = 0; x < 80; x++) { dat = t3100e->vram[addr & 0x7FFF]; @@ -421,7 +421,7 @@ t3100e_cgaline4(t3100e_t *t3100e) for (uint8_t c = 0; c < 4; c++) { pattern = (dat & 0xC0) >> 6; - if (!(t3100e->cga.cgamode & 8)) + if (!(t3100e->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE)) pattern = 0; switch (pattern & 3) { @@ -497,12 +497,12 @@ t3100e_poll(void *priv) } /* Graphics */ - if (t3100e->cga.cgamode & 0x02) { - if (t3100e->cga.cgamode & 0x10) + if (t3100e->cga.cgamode & CGA_MODE_FLAG_GRAPHICS) { + if (t3100e->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) t3100e_cgaline6(t3100e); else t3100e_cgaline4(t3100e); - } else if (t3100e->cga.cgamode & 0x01) /* High-res text */ + } else if (t3100e->cga.cgamode & CGA_MODE_FLAG_HIGHRES) /* High-res text */ { t3100e_text_row80(t3100e); } else { @@ -550,8 +550,8 @@ t3100e_poll(void *priv) video_res_x = T3100E_XSIZE; video_res_y = T3100E_YSIZE; - if (t3100e->cga.cgamode & 0x02) { - if (t3100e->cga.cgamode & 0x10) + if (t3100e->cga.cgamode & CGA_MODE_FLAG_GRAPHICS) { + if (t3100e->cga.cgamode & CGA_MODE_FLAG_HIGHRES_GRAPHICS) video_bpp = 1; else video_bpp = 2; diff --git a/src/video/vid_chips_69000.c b/src/video/vid_chips_69000.c index 170a601fd..70b2b9e16 100644 --- a/src/video/vid_chips_69000.c +++ b/src/video/vid_chips_69000.c @@ -1098,7 +1098,7 @@ chips_69000_recalctimings(svga_t *svga) svga->hblank_end_val = ((svga->crtc[3] & 0x1f) | ((svga->crtc[5] & 0x80) ? 0x20 : 0x00)) | (svga->crtc[0x3c] & 0b11000000); svga->hblank_end_mask = 0xff; - svga->ma_latch |= (svga->crtc[0x40] & 0xF) << 16; + svga->memaddr_latch |= (svga->crtc[0x40] & 0xF) << 16; svga->rowoffset |= (svga->crtc[0x41] & 0xF) << 8; svga->interlace = !!(svga->crtc[0x70] & 0x80); @@ -2044,7 +2044,7 @@ chips_69000_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 2377e792b..b2a221e20 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -575,7 +575,7 @@ gd54xx_overlay_draw(svga_t *svga, int displine) uint8_t *src = &svga->vram[(svga->overlay_latch.addr << shift) & svga->vram_mask]; int bpp = svga->bpp; int bytesperpix = (bpp + 7) / 8; - uint8_t *src2 = &svga->vram[(svga->ma - (svga->hdisp * bytesperpix)) & svga->vram_display_mask]; + uint8_t *src2 = &svga->vram[(svga->memaddr - (svga->hdisp * bytesperpix)) & svga->vram_display_mask]; int occl; int ckval; @@ -1255,7 +1255,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; @@ -1875,7 +1875,7 @@ gd54xx_recalctimings(svga_t *svga) } else if (svga->gdcreg[5] & 0x40) svga->render = svga_render_8bpp_lowres; - svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); + svga->memaddr_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); svga->bpp = 8; @@ -4254,10 +4254,16 @@ gd54xx_init(const device_t *info) break; case CIRRUS_ID_CLGD5422: - case CIRRUS_ID_CLGD5424: romfn = BIOS_GD5422_PATH; break; + case CIRRUS_ID_CLGD5424: + if (info->local & 0x200) + romfn = /*NULL*/ "roms/machines/advantage40xxd/AST101.09A"; + else + romfn = BIOS_GD5422_PATH; + break; + case CIRRUS_ID_CLGD5426: if (info->local & 0x200) romfn = NULL; @@ -5023,6 +5029,20 @@ const device_t gd5424_vlb_device = { .config = gd542x_config, }; +const device_t gd5424_onboard_device = { + .name = "Cirrus Logic GD5424 (VLB) (On-Board)", + .internal_name = "cl_gd5424_onboard", + .flags = DEVICE_VLB, + .local = CIRRUS_ID_CLGD5424 | 0x200, + .init = gd54xx_init, + .close = gd54xx_close, + .reset = gd54xx_reset, + .available = NULL, + .speed_changed = gd54xx_speed_changed, + .force_redraw = gd54xx_force_redraw, + .config = gd542x_config, +}; + const device_t gd5426_isa_device = { .name = "Cirrus Logic GD5426 (ISA)", .internal_name = "cl_gd5426_isa", diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index c21b7c714..21671f4b3 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -158,9 +158,11 @@ ega_out(uint16_t addr, uint8_t val, void *priv) if (ega->alt_addr == 1) base_addr = 0x02a0; #endif - io_removehandler(base_addr, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); - if (!(val & 1)) - io_sethandler(base_addr, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + if (ega->priv_parent == NULL) { + io_removehandler(base_addr, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + if (!(val & 1)) + io_sethandler(base_addr, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + } ega_recalctimings(ega); if ((type == EGA_TYPE_COMPAQ) && !(val & 0x02)) mem_mapping_disable(&ega->mapping); @@ -313,7 +315,7 @@ ega_out(uint16_t addr, uint8_t val, void *priv) if ((idx < 0xe) || (idx > 0x10)) { if ((idx == 0xc) || (idx == 0xd)) { ega->fullchange = 3; - ega->ma_latch = ((ega->crtc[0xc] << 8) | ega->crtc[0xd]) + + ega->memaddr_latch = ((ega->crtc[0xc] << 8) | ega->crtc[0xd]) + ((ega->crtc[8] & 0x60) >> 5); } else { ega->fullchange = changeframecount; @@ -505,7 +507,7 @@ ega_in(uint16_t addr, void *priv) case 0x3da: ega->attrff = 0; if (type == EGA_TYPE_COMPAQ) { - ret = ega->stat & 0xcf; + ret = ega->status & 0xcf; switch ((ega->attrregs[0x12] >> 4) & 0x03) { case 0x00: /* 00 = Pri. Red (5), Pri. Blue (4) */ @@ -526,8 +528,8 @@ ega_in(uint16_t addr, void *priv) break; } } else { - ega->stat ^= 0x30; /* Fools IBM EGA video BIOS self-test. */ - ret = ega->stat; + ega->status ^= 0x30; /* Fools IBM EGA video BIOS self-test. */ + ret = ega->status; } break; case 0x7c6: @@ -649,7 +651,7 @@ ega_recalctimings(ega_t *ega) ega->interlace = 0; - ega->ma_latch = (ega->crtc[0xc] << 8) | ega->crtc[0xd]; + ega->memaddr_latch = (ega->crtc[0xc] << 8) | ega->crtc[0xd]; ega->render = ega_render_blank; if (!ega->scrblank && ega->attr_palette_enable) { @@ -748,7 +750,7 @@ ega_dot_poll(void *priv) const int dwshift = doublewidth ? 1 : 0; const int dotwidth = 1 << dwshift; const int charwidth = dotwidth * (seq9dot ? 9 : 8); - const int cursoron = (ega->sc == (ega->crtc[10] & 31)); + const int cursoron = (ega->scanline == (ega->crtc[10] & 31)); const int cursoraddr = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; uint32_t addr; int drawcursor; @@ -792,7 +794,7 @@ ega_dot_poll(void *priv) else charaddr = ega->charseta + (chr * 0x80); - dat = ega->vram[charaddr + (ega->sc << 2)]; + dat = ega->vram[charaddr + (ega->scanline << 2)]; dat <<= 1; if ((chr & ~0x1F) == 0xC0 && attrlinechars) dat |= (dat >> 1) & 1; @@ -837,19 +839,19 @@ ega_poll(void *priv) if (!ega->linepos) { timer_advance_u64(&ega->timer, ega->dispofftime); - ega->stat |= 1; + ega->status |= 1; ega->linepos = 1; if (ega->dispon) { ega->hdisp_on = 1; - ega->ma &= ega->vrammask; + ega->memaddr &= ega->vrammask; if (ega->firstline == 2000) { ega->firstline = ega->displine; video_wait_for_buffer(); } - old_ma = ega->ma; + old_ma = ega->memaddr; ega->displine *= ega->vres + 1; ega->y_add *= ega->vres + 1; for (int y = 0; y <= ega->vres; y++) { @@ -863,7 +865,7 @@ ega_poll(void *priv) ega->x_add = (overscan_x >> 1) - ega->scrollcache; if (y != ega->vres) { - ega->ma = old_ma; + ega->memaddr = old_ma; ega->displine++; } } @@ -877,8 +879,8 @@ ega_poll(void *priv) ega->displine++; if (ega->interlace) ega->displine++; - if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) - ega->stat &= ~8; + if ((ega->status & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) + ega->status &= ~8; ega->vslines++; if (ega->chipset) { if (ega->hdisp >= 800) { @@ -896,35 +898,35 @@ ega_poll(void *priv) timer_advance_u64(&ega->timer, ega->dispontime); if (ega->dispon) - ega->stat &= ~1; + ega->status &= ~1; ega->hdisp_on = 0; ega->linepos = 0; - if ((ega->sc == (ega->crtc[11] & 31)) || (ega->sc == ega->rowcount)) - ega->con = 0; + if ((ega->scanline == (ega->crtc[11] & 31)) || (ega->scanline == ega->rowcount)) + ega->cursorvisible = 0; if (ega->dispon) { /* TODO: Verify real hardware behaviour for out-of-range fine vertical scroll */ if (ega->linedbl && !ega->linecountff) { ega->linecountff = 1; - ega->ma = ega->maback; - ega->cca = ega->maback; + ega->memaddr = ega->memaddr_backup; + ega->cca = ega->memaddr_backup; } - if (ega->sc == (ega->crtc[9] & 31)) { + if (ega->scanline == (ega->crtc[9] & 31)) { ega->linecountff = 0; - ega->sc = 0; + ega->scanline = 0; - ega->maback += (ega->rowoffset << 3); + ega->memaddr_backup += (ega->rowoffset << 3); if (ega->interlace) - ega->maback += (ega->rowoffset << 3); - ega->maback &= ega->vrammask; - ega->ma = ega->maback; - ega->cca = ega->maback; + ega->memaddr_backup += (ega->rowoffset << 3); + ega->memaddr_backup &= ega->vrammask; + ega->memaddr = ega->memaddr_backup; + ega->cca = ega->memaddr_backup; } else { ega->linecountff = 0; - ega->sc++; - ega->sc &= 31; - ega->ma = ega->maback; - ega->cca = ega->maback; + ega->scanline++; + ega->scanline &= 31; + ega->memaddr = ega->memaddr_backup; + ega->cca = ega->memaddr_backup; } } ega->real_vc++; @@ -941,13 +943,13 @@ ega_poll(void *priv) if (ega->vc == ega->split) { // TODO: Implement the hardware bug where the first scanline is drawn twice when the split happens if (ega->interlace && ega->oddeven) - ega->ma = ega->maback = ega->rowoffset << 1; + ega->memaddr = ega->memaddr_backup = ega->rowoffset << 1; else - ega->ma = ega->maback = 0; - ega->ma <<= 2; - ega->cca = ega->ma; - ega->maback <<= 2; - ega->sc = 0; + ega->memaddr = ega->memaddr_backup = 0; + ega->memaddr <<= 2; + ega->cca = ega->memaddr; + ega->memaddr_backup <<= 2; + ega->scanline = 0; } if (ega->vc == ega->dispend) { ega->dispon = 0; @@ -968,7 +970,7 @@ ega_poll(void *priv) } if (ega->vc == ega->vsyncstart) { ega->dispon = 0; - ega->stat |= 8; + ega->status |= 8; #if 0 picint(1 << 2); #endif @@ -1007,19 +1009,19 @@ ega_poll(void *priv) ega->vslines = 0; if (ega->interlace && ega->oddeven) - ega->ma = ega->maback = ega->ma_latch + (ega->rowoffset << 1); + ega->memaddr = ega->memaddr_backup = ega->memaddr_latch + (ega->rowoffset << 1); else - ega->ma = ega->maback = ega->ma_latch; - ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; + ega->memaddr = ega->memaddr_backup = ega->memaddr_latch; + ega->cursoraddr = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; - ega->ma <<= 2; - ega->maback <<= 2; - ega->ca <<= 2; - ega->cca = ega->ma; + ega->memaddr <<= 2; + ega->memaddr_backup <<= 2; + ega->cursoraddr <<= 2; + ega->cca = ega->memaddr; } if (ega->vc == ega->vtotal) { ega->vc = 0; - ega->sc = (ega->crtc[0x8] & 0x1f); + ega->scanline = (ega->crtc[0x8] & 0x1f); ega->dispon = 1; ega->displine = (ega->interlace && ega->oddeven) ? 1 : 0; @@ -1036,8 +1038,8 @@ ega_poll(void *priv) ega->linecountff = 0; } - if (ega->sc == (ega->crtc[10] & 31)) - ega->con = 1; + if (ega->scanline == (ega->crtc[10] & 31)) + ega->cursorvisible = 1; } } @@ -1512,24 +1514,24 @@ ega_init(ega_t *ega, int monitor_type, int is_mono) ega->pallook = pallook16; for (uint16_t c = 0; c < 256; c++) { - ega->mdacols[c][0][0] = ega->mdacols[c][1][0] = ega->mdacols[c][1][1] = 16; + ega->mda_attr_to_color_table[c][0][0] = ega->mda_attr_to_color_table[c][1][0] = ega->mda_attr_to_color_table[c][1][1] = 16; if (c & 8) - ega->mdacols[c][0][1] = 15 + 16; + ega->mda_attr_to_color_table[c][0][1] = 15 + 16; else - ega->mdacols[c][0][1] = 7 + 16; + ega->mda_attr_to_color_table[c][0][1] = 7 + 16; } - ega->mdacols[0x70][0][1] = 16; - ega->mdacols[0x70][0][0] = ega->mdacols[0x70][1][0] = ega->mdacols[0x70][1][1] = 16 + 15; - ega->mdacols[0xF0][0][1] = 16; - ega->mdacols[0xF0][0][0] = ega->mdacols[0xF0][1][0] = ega->mdacols[0xF0][1][1] = 16 + 15; - ega->mdacols[0x78][0][1] = 16 + 7; - ega->mdacols[0x78][0][0] = ega->mdacols[0x78][1][0] = ega->mdacols[0x78][1][1] = 16 + 15; - ega->mdacols[0xF8][0][1] = 16 + 7; - ega->mdacols[0xF8][0][0] = ega->mdacols[0xF8][1][0] = ega->mdacols[0xF8][1][1] = 16 + 15; - ega->mdacols[0x00][0][1] = ega->mdacols[0x00][1][1] = 16; - ega->mdacols[0x08][0][1] = ega->mdacols[0x08][1][1] = 16; - ega->mdacols[0x80][0][1] = ega->mdacols[0x80][1][1] = 16; - ega->mdacols[0x88][0][1] = ega->mdacols[0x88][1][1] = 16; + ega->mda_attr_to_color_table[0x70][0][1] = 16; + ega->mda_attr_to_color_table[0x70][0][0] = ega->mda_attr_to_color_table[0x70][1][0] = ega->mda_attr_to_color_table[0x70][1][1] = 16 + 15; + ega->mda_attr_to_color_table[0xF0][0][1] = 16; + ega->mda_attr_to_color_table[0xF0][0][0] = ega->mda_attr_to_color_table[0xF0][1][0] = ega->mda_attr_to_color_table[0xF0][1][1] = 16 + 15; + ega->mda_attr_to_color_table[0x78][0][1] = 16 + 7; + ega->mda_attr_to_color_table[0x78][0][0] = ega->mda_attr_to_color_table[0x78][1][0] = ega->mda_attr_to_color_table[0x78][1][1] = 16 + 15; + ega->mda_attr_to_color_table[0xF8][0][1] = 16 + 7; + ega->mda_attr_to_color_table[0xF8][0][0] = ega->mda_attr_to_color_table[0xF8][1][0] = ega->mda_attr_to_color_table[0xF8][1][1] = 16 + 15; + ega->mda_attr_to_color_table[0x00][0][1] = ega->mda_attr_to_color_table[0x00][1][1] = 16; + ega->mda_attr_to_color_table[0x08][0][1] = ega->mda_attr_to_color_table[0x08][1][1] = 16; + ega->mda_attr_to_color_table[0x80][0][1] = ega->mda_attr_to_color_table[0x80][1][1] = 16; + ega->mda_attr_to_color_table[0x88][0][1] = ega->mda_attr_to_color_table[0x88][1][1] = 16; egaswitches = monitor_type & 0xf; diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index 8a73ffbbb..c1c44dfdb 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -141,9 +141,9 @@ ega_render_text(ega_t *ega) } for (int x = 0; x < (ega->hdisp + ega->scrollcache); x += charwidth) { - uint32_t addr = ega->remap_func(ega, ega->ma) & ega->vrammask; + uint32_t addr = ega->remap_func(ega, ega->memaddr) & ega->vrammask; - int drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + int drawcursor = ((ega->memaddr == ega->cursoraddr) && ega->cursorvisible && ega->cursoron); uint32_t chr; uint32_t attr; @@ -175,7 +175,7 @@ ega_render_text(ega_t *ega) } } - uint32_t dat = ega->vram[charaddr + (ega->sc << 2)]; + uint32_t dat = ega->vram[charaddr + (ega->scanline << 2)]; dat <<= 1; if (((chr & ~0x1f) == 0xc0) && attrlinechars) dat |= (dat >> 1) & 1; @@ -184,21 +184,21 @@ ega_render_text(ega_t *ega) if (monoattrs) { int bit = (dat & (0x100 >> (xx >> dwshift))) ? 1 : 0; int blink = (!drawcursor && (attr & 0x80) && attrblink && blinked); - if ((ega->sc == ega->crtc[0x14]) && ((attr & 7) == 1)) - p[xx] = ega->mdacols[attr][blink][1]; + if ((ega->scanline == ega->crtc[0x14]) && ((attr & 7) == 1)) + p[xx] = ega->mda_attr_to_color_table[attr][blink][1]; else - p[xx] = ega->mdacols[attr][blink][bit]; + p[xx] = ega->mda_attr_to_color_table[attr][blink][bit]; if (drawcursor) - p[xx] ^= ega->mdacols[attr][0][1]; + p[xx] ^= ega->mda_attr_to_color_table[attr][0][1]; p[xx] = ega->pallook[ega->egapal[p[xx] & 0x0f]]; } else p[xx] = (dat & (0x100 >> (xx >> dwshift))) ? fg : bg; } - ega->ma += 4; + ega->memaddr += 4; p += charwidth; } - ega->ma &= 0x3ffff; + ega->memaddr &= 0x3ffff; } } @@ -236,7 +236,7 @@ ega_render_graphics(ega_t *ega) } for (int x = 0; x <= (ega->hdisp + ega->scrollcache); x += charwidth) { - uint32_t addr = ega->remap_func(ega, ega->ma) & ega->vrammask; + uint32_t addr = ega->remap_func(ega, ega->memaddr) & ega->vrammask; uint8_t edat[4]; if (seqoddeven) { @@ -247,12 +247,12 @@ ega_render_graphics(ega_t *ega) edat[3] = ega->vram[(addr | 3) ^ secondcclk]; secondcclk = (secondcclk + 1) & 1; if (secondcclk == 0) - ega->ma += 4; + ega->memaddr += 4; } else { *(uint32_t *) (&edat[0]) = *(uint32_t *) (&ega->vram[addr]); - ega->ma += 4; + ega->memaddr += 4; } - ega->ma &= 0x3ffff; + ega->memaddr &= 0x3ffff; if (cga2bpp) { // Remap CGA 2bpp-chunky data into fully planar data diff --git a/src/video/vid_et3000.c b/src/video/vid_et3000.c index 193fed3c7..a82f93385 100644 --- a/src/video/vid_et3000.c +++ b/src/video/vid_et3000.c @@ -424,7 +424,7 @@ et3000_out(uint16_t addr, uint8_t val, void *priv) static void et3000_recalctimings(svga_t *svga) { - svga->ma_latch |= (svga->crtc[0x23] & 2) << 15; + svga->memaddr_latch |= (svga->crtc[0x23] & 2) << 15; if (svga->crtc[0x25] & 1) svga->vblankstart |= 0x400; if (svga->crtc[0x25] & 2) @@ -439,7 +439,7 @@ et3000_recalctimings(svga_t *svga) svga->interlace = !!(svga->crtc[0x25] & 0x80); if (svga->attrregs[0x16] & 0x10) { - svga->ma_latch <<= (1 << 0); + svga->memaddr_latch <<= (1 << 0); svga->rowoffset <<= (1 << 0); switch (svga->gdcreg[5] & 0x60) { case 0x00: diff --git a/src/video/vid_et4000.c b/src/video/vid_et4000.c index 1929d1d16..a99cb8872 100644 --- a/src/video/vid_et4000.c +++ b/src/video/vid_et4000.c @@ -378,7 +378,7 @@ et4000_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -642,7 +642,7 @@ et4000_recalctimings(svga_t *svga) { const et4000_t *dev = (et4000_t *) svga->priv; - svga->ma_latch |= (svga->crtc[0x33] & 3) << 16; + svga->memaddr_latch |= (svga->crtc[0x33] & 3) << 16; svga->hblankstart = (((svga->crtc[0x3f] & 0x4) >> 2) << 8) + svga->crtc[2]; @@ -701,7 +701,7 @@ et4000_recalctimings(svga_t *svga) if (dev->type == ET4000_TYPE_KOREAN || dev->type == ET4000_TYPE_TRIGEM || dev->type == ET4000_TYPE_KASAN) { if ((svga->render == svga_render_text_80) && ((svga->crtc[0x37] & 0x0A) == 0x0A)) { if (dev->port_32cb_val & 0x80) { - svga->ma_latch -= 2; + svga->memaddr_latch -= 2; svga->ca_adj = -2; } if ((dev->port_32cb_val & 0xB4) == ((svga->crtc[0x37] & 3) == 2 ? 0xB4 : 0xB0)) { @@ -719,7 +719,7 @@ et4000_recalctimings(svga_t *svga) } if ((svga->seqregs[0x0e] & 0x02) && ((svga->gdcreg[5] & 0x60) >= 0x40) && svga->lowres) { - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; svga->rowoffset <<= 1; svga->render = svga_render_8bpp_highres; } @@ -734,7 +734,7 @@ et4000_kasan_recalctimings(svga_t *svga) if (svga->render == svga_render_text_80 && (et4000->kasan_cfg_regs[0] & 8)) { svga->hdisp += svga->dots_per_clock; - svga->ma_latch -= 4; + svga->memaddr_latch -= 4; svga->ca_adj = (et4000->kasan_cfg_regs[0] >> 6) - 3; svga->ksc5601_sbyte_mask = (et4000->kasan_cfg_regs[0] & 4) << 5; if ((et4000->kasan_cfg_regs[0] & 0x23) == 0x20 && (et4000->kasan_cfg_regs[4] & 0x80) && ((svga->crtc[0x37] & 0x0B) == 0x0A)) diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 246decb9c..533bd1f28 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -238,7 +238,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -430,7 +430,7 @@ et4000w32p_recalctimings(svga_t *svga) { et4000w32p_t *et4000 = (et4000w32p_t *) svga->priv; - svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; + svga->memaddr_latch |= (svga->crtc[0x33] & 0x7) << 16; svga->hblankstart = (((svga->crtc[0x3f] & 0x4) >> 2) << 8) + svga->crtc[2]; diff --git a/src/video/vid_f82c425.c b/src/video/vid_f82c425.c index c607cda14..078e0f3df 100644 --- a/src/video/vid_f82c425.c +++ b/src/video/vid_f82c425.c @@ -361,28 +361,28 @@ f82c425_text_row(f82c425_t *f82c425) int cursorline; int blink; uint16_t addr; - uint8_t sc; - uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; - uint16_t ca = (f82c425->cga.crtc[0x0f] | (f82c425->cga.crtc[0x0e] << 8)) & 0x3fff; - uint8_t sl = f82c425->cga.crtc[9] + 1; - int columns = f82c425->cga.crtc[1]; + uint8_t scanline; + uint16_t memaddr = (f82c425->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (f82c425->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + uint16_t cursoraddr = (f82c425->cga.crtc[0x0f] | (f82c425->cga.crtc[0x0e] << 8)) & 0x3fff; + uint8_t sl = f82c425->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1; + int columns = f82c425->cga.crtc[CGA_CRTC_HDISP]; - sc = (f82c425->displine) & 7; - addr = ((ma & ~1) + (f82c425->displine >> 3) * columns) * 2; - ma += (f82c425->displine >> 3) * columns; + scanline = (f82c425->displine) & 7; + addr = ((memaddr & ~1) + (f82c425->displine >> 3) * columns) * 2; + memaddr += (f82c425->displine >> 3) * columns; - if ((f82c425->cga.crtc[0x0a] & 0x60) == 0x20) { + if ((f82c425->cga.crtc[CGA_CRTC_CURSOR_START] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((f82c425->cga.crtc[0x0a] & 0x0F) <= sc) && ((f82c425->cga.crtc[0x0b] & 0x0F) >= sc); + cursorline = ((f82c425->cga.crtc[CGA_CRTC_CURSOR_START] & 0x0F) <= scanline) && ((f82c425->cga.crtc[CGA_CRTC_CURSOR_END] & 0x0F) >= scanline); } for (int x = 0; x < columns; x++) { chr = f82c425->vram[(addr + 2 * x) & 0x3FFF]; attr = f82c425->vram[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && (f82c425->cga.cgamode & 0x8) && (f82c425->cga.cgablink & 0x10)); + drawcursor = ((memaddr == cursoraddr) && cursorline && (f82c425->cga.cgamode & CGA_MODE_FLAG_VIDEO_ENABLE) && (f82c425->cga.cgablink & 0x10)); - blink = ((f82c425->cga.cgablink & 0x10) && (f82c425->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + blink = ((f82c425->cga.cgablink & 0x10) && (f82c425->cga.cgamode & CGA_MODE_FLAG_BLINK) && (attr & 0x80) && !drawcursor); if (drawcursor) { colors[0] = smartmap[~attr & 0xff][0]; @@ -398,16 +398,16 @@ f82c425_text_row(f82c425_t *f82c425) if (f82c425->cga.cgamode & 0x01) { /* High resolution (80 cols) */ for (c = 0; c < sl; c++) { - (buffer32->line[f82c425->displine])[(x << 3) + c] = colors[(fontdat[chr][sc] & (1 << (c ^ 7))) ? 1 : 0]; + (buffer32->line[f82c425->displine])[(x << 3) + c] = colors[(fontdat[chr][scanline] & (1 << (c ^ 7))) ? 1 : 0]; } } else { /* Low resolution (40 columns, stretch pixels horizontally) */ for (c = 0; c < sl; c++) { - (buffer32->line[f82c425->displine])[(x << 4) + c * 2] = (buffer32->line[f82c425->displine])[(x << 4) + c * 2 + 1] = colors[(fontdat[chr][sc] & (1 << (c ^ 7))) ? 1 : 0]; + (buffer32->line[f82c425->displine])[(x << 4) + c * 2] = (buffer32->line[f82c425->displine])[(x << 4) + c * 2 + 1] = colors[(fontdat[chr][scanline] & (1 << (c ^ 7))) ? 1 : 0]; } } - ++ma; + ++memaddr; } } @@ -418,9 +418,9 @@ f82c425_cgaline6(f82c425_t *f82c425) uint8_t dat; uint16_t addr; - uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; + uint16_t memaddr = (f82c425->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (f82c425->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; - addr = ((f82c425->displine) & 1) * 0x2000 + (f82c425->displine >> 1) * 80 + ((ma & ~1) << 1); + addr = ((f82c425->displine) & 1) * 0x2000 + (f82c425->displine >> 1) * 80 + ((memaddr & ~1) << 1); for (uint8_t x = 0; x < 80; x++) { dat = f82c425->vram[addr & 0x3FFF]; @@ -442,8 +442,8 @@ f82c425_cgaline4(f82c425_t *f82c425) uint8_t pattern; uint16_t addr; - uint16_t ma = (f82c425->cga.crtc[0x0d] | (f82c425->cga.crtc[0x0c] << 8)) & 0x3fff; - addr = ((f82c425->displine) & 1) * 0x2000 + (f82c425->displine >> 1) * 80 + ((ma & ~1) << 1); + uint16_t memaddr = (f82c425->cga.crtc[CGA_CRTC_START_ADDR_LOW] | (f82c425->cga.crtc[CGA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + addr = ((f82c425->displine) & 1) * 0x2000 + (f82c425->displine >> 1) * 80 + ((memaddr & ~1) << 1); for (uint8_t x = 0; x < 80; x++) { dat = f82c425->vram[addr & 0x3FFF]; @@ -526,7 +526,7 @@ f82c425_poll(void *priv) f82c425->displine = 0; f82c425->cga.cgastat &= ~8; f82c425->dispon = 1; - } else if (f82c425->displine == (f82c425->cga.crtc[9] + 1) * f82c425->cga.crtc[6]) { + } else if (f82c425->displine == (f82c425->cga.crtc[CGA_CRTC_MAX_SCANLINE_ADDR] + 1) * f82c425->cga.crtc[CGA_CRTC_VDISP]) { /* Start of VSYNC */ f82c425->cga.cgastat |= 8; f82c425->dispon = 0; diff --git a/src/video/vid_genius.c b/src/video/vid_genius.c index c7a91aac6..366fa25e1 100644 --- a/src/video/vid_genius.c +++ b/src/video/vid_genius.c @@ -387,7 +387,7 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) int cw = 9; /* Each character is 9 pixels wide */ uint8_t chr; uint8_t attr; - uint8_t sc; + uint8_t scanline; uint8_t ctrl; const uint8_t *crtc; uint8_t bitmap[2]; @@ -398,8 +398,8 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) int drawcursor; int cursorline; uint16_t addr; - uint16_t ma = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; - uint16_t ca = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; + uint16_t memaddr = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; + uint16_t cursoraddr = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; const uint8_t *framebuf = genius->vram + 0x10000; uint32_t col; uint32_t dl = genius->displine; @@ -416,14 +416,14 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) #if 0 if (genius->genius_charh & 0x10) { row = ((dl >> 1) / charh); - sc = ((dl >> 1) % charh); + scanline = ((dl >> 1) % charh); } else { row = (dl / charh); - sc = (dl % charh); + scanline = (dl % charh); } #else row = (dl / charh); - sc = (dl % charh); + scanline = (dl % charh); #endif } else { if ((genius->displine < 512) || (genius->displine >= 912)) @@ -439,23 +439,23 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) charh = crtc[9] + 1; row = ((dl >> 1) / charh); - sc = ((dl >> 1) % charh); + scanline = ((dl >> 1) % charh); } - ma = (crtc[13] | (crtc[12] << 8)) & 0x3fff; - ca = (crtc[15] | (crtc[14] << 8)) & 0x3fff; + memaddr = (crtc[13] | (crtc[12] << 8)) & 0x3fff; + cursoraddr = (crtc[15] | (crtc[14] << 8)) & 0x3fff; - addr = ((ma & ~1) + row * w) * 2; + addr = ((memaddr & ~1) + row * w) * 2; if (!mda) dl += 512; - ma += (row * w); + memaddr += (row * w); if ((crtc[10] & 0x60) == 0x20) cursorline = 0; else - cursorline = ((crtc[10] & 0x1F) <= sc) && ((crtc[11] & 0x1F) >= sc); + cursorline = ((crtc[10] & 0x1F) <= scanline) && ((crtc[11] & 0x1F) >= scanline); for (int x = 0; x < w; x++) { #if 0 @@ -467,7 +467,7 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) chr = framebuf[(addr + 2 * x) & 0x3FFF]; attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && genius->enabled && (ctrl & 8)); + drawcursor = ((memaddr == cursoraddr) && cursorline && genius->enabled && (ctrl & 8)); switch (crtc[10] & 0x60) { case 0x00: @@ -487,7 +487,7 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) attr &= 0x7F; /* MDA underline */ - if (mda && (sc == charh) && ((attr & 7) == 1)) { + if (mda && (scanline == charh) && ((attr & 7) == 1)) { col = mdaattr[attr][blink][1]; if (genius->genius_control & 0x20) @@ -504,9 +504,9 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) } } else { /* Draw 8 pixels of character */ if (mda) - bitmap[0] = fontdat8x12[chr][sc]; + bitmap[0] = fontdat8x12[chr][scanline]; else - bitmap[0] = fontdat[chr][sc]; + bitmap[0] = fontdat[chr][scanline]; for (c = 0; c < 8; c++) { col = mdaattr[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; @@ -563,7 +563,7 @@ genius_textline(genius_t *genius, uint8_t background, int mda, int cols80) } } } - ++ma; + ++memaddr; } } } diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index cf8ad8cf3..229ddcca8 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -168,9 +168,9 @@ hercules_in(uint16_t addr, void *priv) case 0x03b5: case 0x03b7: if (dev->crtcreg == 0x0c) - ret = (dev->ma >> 8) & 0x3f; + ret = (dev->memaddr >> 8) & 0x3f; else if (dev->crtcreg == 0x0d) - ret = dev->ma & 0xff; + ret = dev->memaddr & 0xff; else ret = dev->crtc[dev->crtcreg]; break; @@ -178,8 +178,8 @@ hercules_in(uint16_t addr, void *priv) case 0x03ba: ret = 0x70; /* Hercules ident */ ret |= (dev->lp_ff ? 2 : 0); - ret |= (dev->stat & 0x01); - if (dev->stat & 0x08) + ret |= (dev->status & 0x01); + if (dev->status & 0x08) ret |= 0x80; if ((ret & 0x81) == 0x80) ret |= 0x08; @@ -281,10 +281,10 @@ hercules_poll(void *priv) hercules_t *dev = (hercules_t *) priv; uint8_t chr; uint8_t attr; - uint16_t ca; + uint16_t cursoraddr; uint16_t dat; uint16_t pa; - int oldsc; + int scanline_old; int blink; int x; int xx; @@ -296,16 +296,16 @@ hercules_poll(void *priv) uint32_t *p; VIDEO_MONITOR_PROLOGUE() - ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; + cursoraddr = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; if (!dev->linepos) { timer_advance_u64(&dev->timer, dev->dispofftime); - dev->stat |= 1; + dev->status |= 1; dev->linepos = 1; - oldsc = dev->sc; + scanline_old = dev->scanline; if ((dev->crtc[8] & 3) == 3) - dev->sc = (dev->sc << 1) & 7; + dev->scanline = (dev->scanline << 1) & 7; if (dev->dispon) { if (dev->displine < dev->firstline) { @@ -317,16 +317,16 @@ hercules_poll(void *priv) hercules_render_overscan_left(dev); if (dev->ctrl & 0x02) { - ca = (dev->sc & 3) * 0x2000; + cursoraddr = (dev->scanline & 3) * 0x2000; if (dev->ctrl & 0x80) - ca += 0x8000; + cursoraddr += 0x8000; for (x = 0; x < dev->crtc[1]; x++) { if (dev->ctrl & 8) - dat = (dev->vram[((dev->ma << 1) & 0x1fff) + ca] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 1]; + dat = (dev->vram[((dev->memaddr << 1) & 0x1fff) + cursoraddr] << 8) | dev->vram[((dev->memaddr << 1) & 0x1fff) + cursoraddr + 1]; else dat = 0; - dev->ma++; + dev->memaddr++; for (c = 0; c < 16; c++) buffer32->line[dev->displine + 14][(x << 4) + c + 8] = (dat & (32768 >> c)) ? 7 : 0; for (c = 0; c < 16; c += 8) @@ -341,25 +341,25 @@ hercules_poll(void *priv) attr = dev->charbuffer[(x << 1) + 1]; } else chr = attr = 0; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->memaddr == cursoraddr) && dev->cursorvisible && dev->cursoron); blink = ((dev->blink & 16) && (dev->ctrl & 0x20) && (attr & 0x80) && !drawcursor); - if (dev->sc == 12 && ((attr & 7) == 1)) { + if (dev->scanline == 12 && ((attr & 7) == 1)) { for (c = 0; c < 9; c++) buffer32->line[dev->displine + 14][(x * 9) + c + 8] = dev->cols[attr][blink][1]; } else { for (c = 0; c < 8; c++) - buffer32->line[dev->displine + 14][(x * 9) + c + 8] = dev->cols[attr][blink][(fontdatm[chr][dev->sc] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[dev->displine + 14][(x * 9) + c + 8] = dev->cols[attr][blink][(fontdatm[chr][dev->scanline] & (1 << (c ^ 7))) ? 1 : 0]; if ((chr & ~0x1f) == 0xc0) - buffer32->line[dev->displine + 14][(x * 9) + 8 + 8] = dev->cols[attr][blink][fontdatm[chr][dev->sc] & 1]; + buffer32->line[dev->displine + 14][(x * 9) + 8 + 8] = dev->cols[attr][blink][fontdatm[chr][dev->scanline] & 1]; else buffer32->line[dev->displine + 14][(x * 9) + 8 + 8] = dev->cols[attr][blink][0]; } if (dev->ctrl2 & 0x01) - dev->ma = (dev->ma + 1) & 0x3fff; + dev->memaddr = (dev->memaddr + 1) & 0x3fff; else - dev->ma = (dev->ma + 1) & 0x7ff; + dev->memaddr = (dev->memaddr + 1) & 0x7ff; if (drawcursor) { for (c = 0; c < 9; c++) @@ -377,10 +377,10 @@ hercules_poll(void *priv) video_process_8(x + 16, dev->displine + 14); } - dev->sc = oldsc; + dev->scanline = scanline_old; - if (dev->vc == dev->crtc[7] && !dev->sc) - dev->stat |= 8; + if (dev->vc == dev->crtc[7] && !dev->scanline) + dev->status |= 8; dev->displine++; if (dev->displine >= 500) dev->displine = 0; @@ -388,32 +388,32 @@ hercules_poll(void *priv) timer_advance_u64(&dev->timer, dev->dispontime); if (dev->dispon) - dev->stat &= ~1; + dev->status &= ~1; dev->linepos = 0; if (dev->vsynctime) { dev->vsynctime--; if (!dev->vsynctime) - dev->stat &= ~8; + dev->status &= ~8; } - if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; + if (dev->scanline == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->scanline == ((dev->crtc[11] & 31) >> 1))) { + dev->cursorvisible = 0; } if (dev->vadj) { - dev->sc++; - dev->sc &= 31; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 31; + dev->memaddr = dev->memaddr_backup; dev->vadj--; if (!dev->vadj) { dev->dispon = 1; - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; - dev->sc = 0; + dev->memaddr = dev->memaddr_backup = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->scanline = 0; } - } else if (((dev->crtc[8] & 3) != 3 && dev->sc == dev->crtc[9]) || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { - dev->maback = dev->ma; - dev->sc = 0; + } else if (((dev->crtc[8] & 3) != 3 && dev->scanline == dev->crtc[9]) || ((dev->crtc[8] & 3) == 3 && dev->scanline == (dev->crtc[9] >> 1))) { + dev->memaddr_backup = dev->memaddr; + dev->scanline = 0; oldvc = dev->vc; dev->vc++; dev->vc &= 127; @@ -426,7 +426,7 @@ hercules_poll(void *priv) dev->vadj = dev->crtc[5]; if (!dev->vadj) { dev->dispon = 1; - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->memaddr = dev->memaddr_backup = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; } switch (dev->crtc[10] & 0x60) { case 0x20: @@ -511,17 +511,17 @@ hercules_poll(void *priv) dev->blink++; } } else { - dev->sc++; - dev->sc &= 31; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 31; + dev->memaddr = dev->memaddr_backup; } - if (dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))) - dev->con = 1; + if (dev->scanline == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->scanline == ((dev->crtc[10] & 31) >> 1))) + dev->cursorvisible = 1; if (dev->dispon && !(dev->ctrl & 0x02)) { for (x = 0; x < (dev->crtc[1] << 1); x++) { pa = (dev->ctrl & 0x80) ? ((x & 1) ? 0x0000 : 0x8000) : 0x0000; - dev->charbuffer[x] = dev->vram[(((dev->ma << 1) + x) & 0x3fff) + pa]; + dev->charbuffer[x] = dev->vram[(((dev->memaddr << 1) + x) & 0x3fff) + pa]; } } } @@ -555,6 +555,9 @@ hercules_init(UNUSED(const device_t *info)) case 3: loadfont(FONT_KAMCL16_PATH, 0); break; + case 4: + loadfont(FONT_TULIP_DGA_PATH, 0); + break; } timer_add(&dev->timer, hercules_poll, dev, 1); @@ -649,17 +652,6 @@ static const device_config_t hercules_config[] = { }, .bios = { { 0 } } }, - { - .name = "blend", - .description = "Blend", - .type = CONFIG_BINARY, - .default_string = NULL, - .default_int = 1, - .file_filter = NULL, - .spinner = { 0 }, - .selection = { { 0 } }, - .bios = { { 0 } } - }, { .name = "font", .description = "Font", @@ -673,10 +665,22 @@ static const device_config_t hercules_config[] = { { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, { .description = "Czech Kamenicky (CP 895) #1", .value = 2 }, { .description = "Czech Kamenicky (CP 895) #2", .value = 3 }, + { .description = "Tulip DGA", .value = 4 }, { .description = "" } }, .bios = { { 0 } } }, + { + .name = "blend", + .description = "Blend", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; diff --git a/src/video/vid_incolor.c b/src/video/vid_hercules_incolor.c similarity index 87% rename from src/video/vid_incolor.c rename to src/video/vid_hercules_incolor.c index 034d54045..eceb440f9 100644 --- a/src/video/vid_incolor.c +++ b/src/video/vid_hercules_incolor.c @@ -157,7 +157,7 @@ typedef struct { uint8_t crtc[32]; int crtcreg; - uint8_t ctrl, ctrl2, stat; + uint8_t ctrl, ctrl2, status; uint64_t dispontime, dispofftime; pc_timer_t timer; @@ -165,9 +165,9 @@ typedef struct { int firstline, lastline; int linepos, displine; - int vc, sc; - uint16_t ma, maback; - int con, cursoron; + int vc, scanline; + uint16_t memaddr, memaddr_backup; + int cursorvisible, cursoron; int dispon, blink; int vsynctime; int vadj; @@ -285,7 +285,7 @@ incolor_in(uint16_t port, void *priv) case 0x3ba: /* 0x50: InColor card identity */ - ret = (dev->stat & 0xf) | ((dev->stat & 8) << 4) | 0x50; + ret = (dev->status & 0xf) | ((dev->status & 8) << 4) | 0x50; break; default: @@ -483,11 +483,11 @@ draw_char_rom(incolor_t *dev, int x, uint8_t chr, uint8_t attr) elg = ((chr >= 0xc0) && (chr <= 0xdf)); } - fnt = &(fontdatm[chr][dev->sc]); + fnt = &(fontdatm[chr][dev->scanline]); if (blk) { val = 0x000; /* Blinking, draw all background */ - } else if (dev->sc == ull) { + } else if (dev->scanline == ull) { val = 0x1ff; /* Underscore, draw all foreground */ } else { val = fnt[0] << 1; @@ -559,12 +559,12 @@ draw_char_ram4(incolor_t *dev, int x, uint8_t chr, uint8_t attr) } else { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } - fnt = dev->vram + 0x4000 + 16 * chr + dev->sc; + fnt = dev->vram + 0x4000 + 16 * chr + dev->scanline; if (blk) { /* Blinking, draw all background */ val[0] = val[1] = val[2] = val[3] = 0x000; - } else if (dev->sc == ull) { + } else if (dev->scanline == ull) { /* Underscore, draw all foreground */ val[0] = val[1] = val[2] = val[3] = 0x1ff; } else { @@ -685,12 +685,12 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) } else { elg = ((chr >= 0xc0) && (chr <= 0xdf)); } - fnt = dev->vram + 0x4000 + 16 * chr + 4096 * font + dev->sc; + fnt = dev->vram + 0x4000 + 16 * chr + 4096 * font + dev->scanline; if (blk) { /* Blinking, draw all background */ val[0] = val[1] = val[2] = val[3] = 0x000; - } else if (dev->sc == ull) { + } else if (dev->scanline == ull) { /* Underscore, draw all foreground */ val[0] = val[1] = val[2] = val[3] = 0x1ff; } else { @@ -716,9 +716,9 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) /* Generate pixel colour */ cfg = 0; pmask = 1; - if (dev->sc == oll) { + if (dev->scanline == oll) { cfg = olc ^ ibg; /* Strikethrough */ - } else if (dev->sc == ull) { + } else if (dev->scanline == ull) { cfg = ulc ^ ibg; /* Underline */ } else { for (uint8_t plane = 0; plane < 4; plane++, pmask = pmask << 1) { @@ -746,7 +746,7 @@ draw_char_ram48(incolor_t *dev, int x, uint8_t chr, uint8_t attr) } static void -text_line(incolor_t *dev, uint16_t ca) +text_line(incolor_t *dev, uint16_t cursoraddr) { int drawcursor; uint8_t chr; @@ -755,12 +755,12 @@ text_line(incolor_t *dev, uint16_t ca) for (uint8_t x = 0; x < dev->crtc[1]; x++) { if (dev->ctrl & 8) { - chr = dev->vram[(dev->ma << 1) & 0x3fff]; - attr = dev->vram[((dev->ma << 1) + 1) & 0x3fff]; + chr = dev->vram[(dev->memaddr << 1) & 0x3fff]; + attr = dev->vram[((dev->memaddr << 1) + 1) & 0x3fff]; } else chr = attr = 0; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->memaddr == cursoraddr) && dev->cursorvisible && dev->cursoron); switch (dev->crtc[INCOLOR_CRTC_XMODE] & 5) { case 0: @@ -779,7 +779,7 @@ text_line(incolor_t *dev, uint16_t ca) default: break; } - ++dev->ma; + ++dev->memaddr; if (drawcursor) { int cw = INCOLOR_CW; @@ -808,29 +808,29 @@ static void graphics_line(incolor_t *dev) { uint8_t mask; - uint16_t ca; + uint16_t cursoraddr; int plane; int col; uint8_t ink; uint16_t val[4]; /* Graphics mode. */ - ca = (dev->sc & 3) * 0x2000; + cursoraddr = (dev->scanline & 3) * 0x2000; if ((dev->ctrl & INCOLOR_CTRL_PAGE1) && (dev->ctrl2 & INCOLOR_CTRL2_PAGE1)) - ca += 0x8000; + cursoraddr += 0x8000; for (uint8_t x = 0; x < dev->crtc[1]; x++) { mask = dev->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */ for (plane = 0; plane < 4; plane++, mask = mask >> 1) { if (dev->ctrl & 8) { if (mask & 1) - val[plane] = (dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + val[plane] = (dev->vram[((dev->memaddr << 1) & 0x1fff) + cursoraddr + 0x10000 * plane] << 8) | dev->vram[((dev->memaddr << 1) & 0x1fff) + cursoraddr + 0x10000 * plane + 1]; else val[plane] = 0; } else val[plane] = 0; } - dev->ma++; + dev->memaddr++; for (uint8_t c = 0; c < 16; c++) { ink = 0; @@ -855,19 +855,19 @@ static void incolor_poll(void *priv) { incolor_t *dev = (incolor_t *) priv; - uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; + uint16_t cursoraddr = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; int x; int oldvc; - int oldsc; + int scanline_old; int cw = INCOLOR_CW; if (!dev->linepos) { timer_advance_u64(&dev->timer, dev->dispofftime); - dev->stat |= 1; + dev->status |= 1; dev->linepos = 1; - oldsc = dev->sc; + scanline_old = dev->scanline; if ((dev->crtc[8] & 3) == 3) - dev->sc = (dev->sc << 1) & 7; + dev->scanline = (dev->scanline << 1) & 7; if (dev->dispon) { if (dev->displine < dev->firstline) { @@ -878,43 +878,43 @@ incolor_poll(void *priv) if ((dev->ctrl & INCOLOR_CTRL_GRAPH) && (dev->ctrl2 & INCOLOR_CTRL2_GRAPH)) graphics_line(dev); else - text_line(dev, ca); + text_line(dev, cursoraddr); } - dev->sc = oldsc; - if (dev->vc == dev->crtc[7] && !dev->sc) - dev->stat |= 8; + dev->scanline = scanline_old; + if (dev->vc == dev->crtc[7] && !dev->scanline) + dev->status |= 8; dev->displine++; if (dev->displine >= 500) dev->displine = 0; } else { timer_advance_u64(&dev->timer, dev->dispontime); if (dev->dispon) - dev->stat &= ~1; + dev->status &= ~1; dev->linepos = 0; if (dev->vsynctime) { dev->vsynctime--; if (!dev->vsynctime) - dev->stat &= ~8; + dev->status &= ~8; } - if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; + if (dev->scanline == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->scanline == ((dev->crtc[11] & 31) >> 1))) { + dev->cursorvisible = 0; } if (dev->vadj) { - dev->sc++; - dev->sc &= 31; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 31; + dev->memaddr = dev->memaddr_backup; dev->vadj--; if (!dev->vadj) { dev->dispon = 1; - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; - dev->sc = 0; + dev->memaddr = dev->memaddr_backup = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->scanline = 0; } - } else if (dev->sc == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { - dev->maback = dev->ma; - dev->sc = 0; - oldvc = dev->vc; + } else if (dev->scanline == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->scanline == (dev->crtc[9] >> 1))) { + dev->memaddr_backup = dev->memaddr; + dev->scanline = 0; + oldvc = dev->vc; dev->vc++; dev->vc &= 127; if (dev->vc == dev->crtc[6]) @@ -925,7 +925,7 @@ incolor_poll(void *priv) if (!dev->vadj) dev->dispon = 1; if (!dev->vadj) - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->memaddr = dev->memaddr_backup = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; if ((dev->crtc[10] & 0x60) == 0x20) dev->cursoron = 0; else @@ -971,13 +971,13 @@ incolor_poll(void *priv) dev->blink++; } } else { - dev->sc++; - dev->sc &= 31; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 31; + dev->memaddr = dev->memaddr_backup; } - if (dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))) - dev->con = 1; + if (dev->scanline == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->scanline == ((dev->crtc[10] & 31) >> 1))) + dev->cursorvisible = 1; } } @@ -992,6 +992,24 @@ incolor_init(UNUSED(const device_t *info)) dev->vram = (uint8_t *) malloc(0x40000); /* 4 planes of 64k */ + switch(device_get_config_int("font")) { + case 0: + loadfont(FONT_IBM_MDA_437_PATH, 0); + break; + case 1: + loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + break; + case 2: + loadfont(FONT_KAM_PATH, 0); + break; + case 3: + loadfont(FONT_KAMCL16_PATH, 0); + break; + case 4: + loadfont(FONT_TULIP_DGA_PATH, 0); + break; + } + timer_add(&dev->timer, incolor_poll, dev, 1); mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, @@ -1044,6 +1062,30 @@ speed_changed(void *priv) recalc_timings(dev); } +static const device_config_t incolor_config[] = { + // clang-format off + { + .name = "font", + .description = "Font", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "US (CP 437)", .value = 0 }, + { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, + { .description = "Czech Kamenicky (CP 895) #1", .value = 2 }, + { .description = "Czech Kamenicky (CP 895) #2", .value = 3 }, + { .description = "Tulip DGA", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + const device_t incolor_device = { .name = "Hercules InColor", .internal_name = "incolor", @@ -1055,5 +1097,5 @@ const device_t incolor_device = { .available = NULL, .speed_changed = speed_changed, .force_redraw = NULL, - .config = NULL + .config = incolor_config }; diff --git a/src/video/vid_herculesplus.c b/src/video/vid_hercules_plus.c similarity index 83% rename from src/video/vid_herculesplus.c rename to src/video/vid_hercules_plus.c index 42c68bf54..7e1aec943 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_hercules_plus.c @@ -67,7 +67,7 @@ typedef struct { uint8_t crtc[32]; int crtcreg; - uint8_t ctrl, ctrl2, stat; + uint8_t ctrl, ctrl2, status; uint64_t dispontime, dispofftime; pc_timer_t timer; @@ -75,9 +75,9 @@ typedef struct { int firstline, lastline; int linepos, displine; - int vc, sc; - uint16_t ma, maback; - int con, cursoron; + int vc, scanline; + uint16_t memaddr, memaddr_backup; + int cursorvisible, cursoron; int dispon, blink; int vsynctime; int vadj; @@ -194,7 +194,7 @@ herculesplus_in(uint16_t port, void *priv) case 0x3ba: /* 0x10: Hercules Plus card identity */ - ret = (dev->stat & 0xf) | ((dev->stat & 8) << 4) | 0x10; + ret = (dev->status & 0xf) | ((dev->status & 8) << 4) | 0x10; break; default: @@ -260,11 +260,11 @@ draw_char_rom(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) else elg = ((chr >= 0xc0) && (chr <= 0xdf)); - fnt = &(fontdatm[chr][dev->sc]); + fnt = &(fontdatm[chr][dev->scanline]); if (blk) { val = 0x000; /* Blinking, draw all background */ - } else if (dev->sc == ull) { + } else if (dev->scanline == ull) { val = 0x1ff; /* Underscore, draw all foreground */ } else { val = fnt[0] << 1; @@ -319,11 +319,11 @@ draw_char_ram4(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) else elg = ((chr >= 0xc0) && (chr <= 0xdf)); - fnt = dev->vram + 0x4000 + 16 * chr + dev->sc; + fnt = dev->vram + 0x4000 + 16 * chr + dev->scanline; if (blk) { val = 0x000; /* Blinking, draw all background */ - } else if (dev->sc == ull) { + } else if (dev->scanline == ull) { val = 0x1ff; /* Underscore, draw all foreground */ } else { val = fnt[0] << 1; @@ -384,11 +384,11 @@ draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) else elg = ((chr >= 0xc0) && (chr <= 0xdf)); - fnt = dev->vram + 0x4000 + 16 * chr + 4096 * font + dev->sc; + fnt = dev->vram + 0x4000 + 16 * chr + 4096 * font + dev->scanline; if (blk) { val = 0x000; /* Blinking, draw all background */ - } else if (dev->sc == ull) { + } else if (dev->scanline == ull) { val = 0x1ff; /* Underscore, draw all foreground */ } else { val = fnt[0] << 1; @@ -404,7 +404,7 @@ draw_char_ram48(herculesplus_t *dev, int x, uint8_t chr, uint8_t attr) } static void -text_line(herculesplus_t *dev, uint16_t ca) +text_line(herculesplus_t *dev, uint16_t cursoraddr) { int drawcursor; uint8_t chr; @@ -413,12 +413,12 @@ text_line(herculesplus_t *dev, uint16_t ca) for (uint8_t x = 0; x < dev->crtc[1]; x++) { if (dev->ctrl & 8) { - chr = dev->vram[(dev->ma << 1) & 0x3fff]; - attr = dev->vram[((dev->ma << 1) + 1) & 0x3fff]; + chr = dev->vram[(dev->memaddr << 1) & 0x3fff]; + attr = dev->vram[((dev->memaddr << 1) + 1) & 0x3fff]; } else chr = attr = 0; - drawcursor = ((dev->ma == ca) && dev->con && dev->cursoron); + drawcursor = ((dev->memaddr == cursoraddr) && dev->cursorvisible && dev->cursoron); switch (dev->crtc[HERCULESPLUS_CRTC_XMODE] & 5) { case 0: @@ -437,7 +437,7 @@ text_line(herculesplus_t *dev, uint16_t ca) default: break; } - ++dev->ma; + ++dev->memaddr; if (drawcursor) { int cw = HERCULESPLUS_CW; @@ -452,24 +452,24 @@ text_line(herculesplus_t *dev, uint16_t ca) static void graphics_line(herculesplus_t *dev) { - uint16_t ca; + uint16_t cursoraddr; int c; int plane = 0; uint16_t val; /* Graphics mode. */ - ca = (dev->sc & 3) * 0x2000; + cursoraddr = (dev->scanline & 3) * 0x2000; if ((dev->ctrl & HERCULESPLUS_CTRL_PAGE1) && (dev->ctrl2 & HERCULESPLUS_CTRL2_PAGE1)) - ca += 0x8000; + cursoraddr += 0x8000; for (uint8_t x = 0; x < dev->crtc[1]; x++) { if (dev->ctrl & 8) - val = (dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) - | dev->vram[((dev->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + val = (dev->vram[((dev->memaddr << 1) & 0x1fff) + cursoraddr + 0x10000 * plane] << 8) + | dev->vram[((dev->memaddr << 1) & 0x1fff) + cursoraddr + 0x10000 * plane + 1]; else val = 0; - dev->ma++; + dev->memaddr++; for (c = 0; c < 16; c++) { buffer32->line[dev->displine][(x << 4) + c] = (val & 0x8000) ? 7 : 0; @@ -485,20 +485,20 @@ static void herculesplus_poll(void *priv) { herculesplus_t *dev = (herculesplus_t *) priv; - uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; + uint16_t cursoraddr = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; int x; int oldvc; - int oldsc; + int scanline_old; int cw = HERCULESPLUS_CW; VIDEO_MONITOR_PROLOGUE(); if (!dev->linepos) { timer_advance_u64(&dev->timer, dev->dispofftime); - dev->stat |= 1; + dev->status |= 1; dev->linepos = 1; - oldsc = dev->sc; + scanline_old = dev->scanline; if ((dev->crtc[8] & 3) == 3) - dev->sc = (dev->sc << 1) & 7; + dev->scanline = (dev->scanline << 1) & 7; if (dev->dispon) { if (dev->displine < dev->firstline) { dev->firstline = dev->displine; @@ -508,7 +508,7 @@ herculesplus_poll(void *priv) if ((dev->ctrl & HERCULESPLUS_CTRL_GRAPH) && (dev->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) graphics_line(dev); else - text_line(dev, ca); + text_line(dev, cursoraddr); if ((dev->ctrl & HERCULESPLUS_CTRL_GRAPH) && (dev->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) x = dev->crtc[1] << 4; @@ -517,39 +517,39 @@ herculesplus_poll(void *priv) video_process_8(x, dev->displine); } - dev->sc = oldsc; - if (dev->vc == dev->crtc[7] && !dev->sc) - dev->stat |= 8; + dev->scanline = scanline_old; + if (dev->vc == dev->crtc[7] && !dev->scanline) + dev->status |= 8; dev->displine++; if (dev->displine >= 500) dev->displine = 0; } else { timer_advance_u64(&dev->timer, dev->dispontime); if (dev->dispon) - dev->stat &= ~1; + dev->status &= ~1; dev->linepos = 0; if (dev->vsynctime) { dev->vsynctime--; if (!dev->vsynctime) - dev->stat &= ~8; + dev->status &= ~8; } - if (dev->sc == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[11] & 31) >> 1))) { - dev->con = 0; + if (dev->scanline == (dev->crtc[11] & 31) || ((dev->crtc[8] & 3) == 3 && dev->scanline == ((dev->crtc[11] & 31) >> 1))) { + dev->cursorvisible = 0; } if (dev->vadj) { - dev->sc++; - dev->sc &= 31; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 31; + dev->memaddr = dev->memaddr_backup; dev->vadj--; if (!dev->vadj) { dev->dispon = 1; - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; - dev->sc = 0; + dev->memaddr = dev->memaddr_backup = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->scanline = 0; } - } else if (dev->sc == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->sc == (dev->crtc[9] >> 1))) { - dev->maback = dev->ma; - dev->sc = 0; + } else if (dev->scanline == dev->crtc[9] || ((dev->crtc[8] & 3) == 3 && dev->scanline == (dev->crtc[9] >> 1))) { + dev->memaddr_backup = dev->memaddr; + dev->scanline = 0; oldvc = dev->vc; dev->vc++; dev->vc &= 127; @@ -561,7 +561,7 @@ herculesplus_poll(void *priv) if (!dev->vadj) dev->dispon = 1; if (!dev->vadj) - dev->ma = dev->maback = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; + dev->memaddr = dev->memaddr_backup = (dev->crtc[13] | (dev->crtc[12] << 8)) & 0x3fff; if ((dev->crtc[10] & 0x60) == 0x20) dev->cursoron = 0; else @@ -606,13 +606,13 @@ herculesplus_poll(void *priv) dev->blink++; } } else { - dev->sc++; - dev->sc &= 31; - dev->ma = dev->maback; + dev->scanline++; + dev->scanline &= 31; + dev->memaddr = dev->memaddr_backup; } - if (dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1))) - dev->con = 1; + if (dev->scanline == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->scanline == ((dev->crtc[10] & 31) >> 1))) + dev->cursorvisible = 1; } VIDEO_MONITOR_EPILOGUE(); @@ -629,6 +629,24 @@ herculesplus_init(UNUSED(const device_t *info)) dev->vram = (uint8_t *) malloc(0x10000); /* 64k VRAM */ dev->monitor_index = monitor_index_global; + switch(device_get_config_int("font")) { + case 0: + loadfont(FONT_IBM_MDA_437_PATH, 0); + break; + case 1: + loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); + break; + case 2: + loadfont(FONT_KAM_PATH, 0); + break; + case 3: + loadfont(FONT_KAMCL16_PATH, 0); + break; + case 4: + loadfont(FONT_TULIP_DGA_PATH, 0); + break; + } + timer_add(&dev->timer, herculesplus_poll, dev, 1); mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, @@ -715,6 +733,24 @@ static const device_config_t herculesplus_config[] = { }, .bios = { { 0 } } }, + { + .name = "font", + .description = "Font", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "US (CP 437)", .value = 0 }, + { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, + { .description = "Czech Kamenicky (CP 895) #1", .value = 2 }, + { .description = "Czech Kamenicky (CP 895) #2", .value = 3 }, + { .description = "Tulip DGA", .value = 4 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "blend", .description = "Blend", diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index b650cb53b..3089ae26d 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -448,7 +448,7 @@ ht216_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -660,10 +660,10 @@ ht216_recalctimings(svga_t *svga) break; } - svga->ma_latch |= ((ht216->ht_regs[0xf6] & 0x30) << 12); + svga->memaddr_latch |= ((ht216->ht_regs[0xf6] & 0x30) << 12); if (ht216->ht_regs[0xf6] & 0x80) - svga->ma_latch = ((ht216->ht_regs[0xf6] & 0x30) << 12); + svga->memaddr_latch = ((ht216->ht_regs[0xf6] & 0x30) << 12); svga->interlace = ht216->ht_regs[0xe0] & 0x01; diff --git a/src/video/vid_jega.c b/src/video/vid_jega.c index 4240f5e98..f49c92e64 100644 --- a/src/video/vid_jega.c +++ b/src/video/vid_jega.c @@ -113,10 +113,10 @@ typedef struct jega_t { uint8_t attr_palette_enable; uint32_t *pallook; int is_vga; - int con; + int cursorvisible; int cursoron; int cursorblink_disable; - int ca; + int cursoraddr; int font_index; int sbcsbank_inv; int attr3_sbcsbank; @@ -151,6 +151,8 @@ extern uint32_t pallook64[256]; static bool is_SJIS_1(uint8_t chr) { return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); } static bool is_SJIS_2(uint8_t chr) { return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); } +static uint8_t jega_in(uint16_t addr, void *priv); + static uint16_t SJIS_to_SEQ(uint16_t sjis) { @@ -222,14 +224,14 @@ jega_render_text(void *priv) &jega->ega.x_add; int * y_add = jega->is_vga ? &jega->vga.svga.y_add : &jega->ega.y_add; - int * sc = jega->is_vga ? &jega->vga.svga.sc : - &jega->ega.sc; + int * sc = jega->is_vga ? &jega->vga.svga.scanline : + &jega->ega.scanline; int * hdisp = jega->is_vga ? &jega->vga.svga.hdisp : &jega->ega.hdisp; int * scrollcache = jega->is_vga ? &jega->vga.svga.scrollcache : &jega->ega.scrollcache; - uint32_t *ma = jega->is_vga ? &jega->vga.svga.ma : - &jega->ega.ma; + uint32_t *memaddr = jega->is_vga ? &jega->vga.svga.memaddr : + &jega->ega.memaddr; uint8_t mask = jega->is_vga ? jega->vga.svga.dac_mask : 0xff; if (*firstline_draw == 2000) @@ -260,12 +262,12 @@ jega_render_text(void *priv) if (jega->is_vga) { if (!jega->vga.svga.force_old_addr) - addr = jega->vga.svga.remap_func(&jega->vga.svga, jega->vga.svga.ma) & + addr = jega->vga.svga.remap_func(&jega->vga.svga, jega->vga.svga.memaddr) & jega->vga.svga.vram_display_mask; } else - addr = jega->ega.remap_func(&jega->ega, *ma) & jega->ega.vrammask; + addr = jega->ega.remap_func(&jega->ega, *memaddr) & jega->ega.vrammask; - int drawcursor = ((*ma == jega->ca) && cursoron); + int drawcursor = ((*memaddr == jega->cursoraddr) && cursoron); uint32_t chr; uint32_t attr; @@ -399,9 +401,9 @@ jega_render_text(void *priv) p += charwidth; } } - *ma += 4; + *memaddr += 4; } - *ma &= 0x3ffff; + *memaddr &= 0x3ffff; } } @@ -422,7 +424,10 @@ jega_out(uint16_t addr, uint8_t val, void *priv) if (!jega->attrff) { jega->attraddr = val & 31; if ((val & 0x20) != jega->attr_palette_enable) { - jega->ega.fullchange = 3; + if (jega->is_vga) + jega->vga.svga.fullchange = 3; + else + jega->ega.fullchange = 3; jega->attr_palette_enable = val & 0x20; jega_recalctimings(jega); } @@ -449,6 +454,13 @@ jega_out(uint16_t addr, uint8_t val, void *priv) } jega->attrff ^= 1; break; + case 0x3c2: + if (jega->regs[RMOD1] & 0x0c) { + io_removehandler(0x03a0, 0x0020, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); + if (!(val & 1)) + io_sethandler(0x03a0, 0x0020, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); + } + break; case 0x3b4: case 0x3d4: /* Index 0x00-0x1F (write only), 0xB8-0xDF (write and read) */ @@ -523,7 +535,7 @@ jega_out(uint16_t addr, uint8_t val, void *priv) break; case RCCLH: case RCCLL: - jega->ca = jega->regs[RCCLH] << 10 | jega->regs[RCCLL] << 2; + jega->cursoraddr = jega->regs[RCCLH] << 10 | jega->regs[RCCLL] << 2; break; case RCMOD: jega->cursoron = (val & 0x80); @@ -742,9 +754,19 @@ jega_commoninit(const device_t *info, void *priv, int vga) jega->is_vga = vga; if (vga) { video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_vga); - vga_init(info, &jega->vga, 1); + svga_init(info, &jega->vga.svga, &jega->vga, 1 << 18, /*256kb*/ + NULL, + jega_in, jega_out, + NULL, + NULL); + + jega->vga.svga.bpp = 8; + jega->vga.svga.miscout = 1; + + jega->vga.svga.vga_enabled = 0; jega->vga.svga.priv_parent = jega; jega->pallook = jega->vga.svga.pallook; + io_sethandler(0x03c0, 0x0020, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); } else { for (int c = 0; c < 256; c++) { pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); @@ -758,9 +780,11 @@ jega_commoninit(const device_t *info, void *priv, int vga) mem_mapping_add(&jega->ega.mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, &jega->ega); + /* I/O 3DD and 3DE are used by Oki if386 */ + io_sethandler(0x03c0, 0x001c, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); } /* I/O 3DD and 3DE are used by Oki if386 */ - io_sethandler(0x03b0, 0x002c, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); + // io_sethandler(0x03b0, 0x002c, jega_in, NULL, NULL, jega_out, NULL, NULL, jega); jega->regs[RMOD1] = 0x48; } diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index 5bf98bc5f..5330e2ab3 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -6,16 +6,19 @@ * * This file is part of the 86Box distribution. * - * MDA emulation. + * IBM Monochrome Display and Printer Adapter emulation. * * * * Authors: Sarah Walker, * Miran Grca, + * Connor Hyde, * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2025 Miran Grca. + * Copyright 2025 starfrost / Connor Hyde */ +#include #include #include #include @@ -33,7 +36,17 @@ #include <86box/vid_mda.h> #include <86box/plat_unused.h> -static int mdacols[256][2][2]; +// Enumerates MDA monitor types +enum mda_monitor_type_e { + MDA_MONITOR_TYPE_DEFAULT = 0, // Default MDA monitor type. + MDA_MONITOR_TYPE_GREEN = 1, // Green phosphor + MDA_MONITOR_TYPE_AMBER = 2, // Amber phosphor + MDA_MONITOR_TYPE_GRAY = 3, // Gray phosphor + MDA_MONITOR_TYPE_RGBI = 4, // RGBI colour monitor with modified rev1 or rev0 MDA card for colour support +} mda_monitor_type; + +// [attr][blink][fg] +static int mda_attr_to_color_table[256][2][2]; static video_timings_t timing_mda = { .type = VIDEO_ISA, .write_b = 8, .write_w = 16, .write_l = 32, .read_b = 8, .read_w = 16, .read_l = 32 }; @@ -44,32 +57,31 @@ mda_out(uint16_t addr, uint8_t val, void *priv) { mda_t *mda = (mda_t *) priv; - switch (addr) { - case 0x3b0: - case 0x3b2: - case 0x3b4: - case 0x3b6: - mda->crtcreg = val & 31; - return; - case 0x3b1: - case 0x3b3: - case 0x3b5: - case 0x3b7: - mda->crtc[mda->crtcreg] = val; - if (mda->crtc[10] == 6 && mda->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ - { - mda->crtc[10] = 0xb; - mda->crtc[11] = 0xc; - } - mda_recalctimings(mda); - return; - case 0x3b8: - mda->ctrl = val; - return; + if (addr < MDA_REGISTER_START + || addr > MDA_REGISTER_CRT_STATUS) // Maintain old behaviour for printer registers, just in case + return; + switch (addr) { + case MDA_REGISTER_MODE_CONTROL: + mda->mode = val; + return; default: break; } + + // addr & 1 == 1 = MDA_REGISTER_CRTC_DATA + // otherwise MDA_REGISTER_CRTC_INDEX + if (addr & 1) { + mda->crtc[mda->crtcreg] = val; + if (mda->crtc[MDA_CRTC_CURSOR_START] == 6 + && mda->crtc[MDA_CRTC_CURSOR_END] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + mda->crtc[MDA_CRTC_CURSOR_START] = 0xb; + mda->crtc[MDA_CRTC_CURSOR_END] = 0xc; + } + mda_recalctimings(mda); + } else + mda->crtcreg = val & 31; } uint8_t @@ -78,23 +90,23 @@ mda_in(uint16_t addr, void *priv) const mda_t *mda = (mda_t *) priv; switch (addr) { - case 0x3b0: - case 0x3b2: - case 0x3b4: - case 0x3b6: - return mda->crtcreg; - case 0x3b1: - case 0x3b3: - case 0x3b5: - case 0x3b7: - return mda->crtc[mda->crtcreg]; - case 0x3ba: - return mda->stat | 0xF0; - + case MDA_REGISTER_CRT_STATUS: + return mda->status | 0xF0; default: + if (addr < MDA_REGISTER_START + || addr > MDA_REGISTER_CRT_STATUS) // Maintain old behaviour for printer registers, just in case + return 0xFF; + + // MDA_REGISTER_CRTC_DATA + if (addr & 1) + return mda->crtc[mda->crtcreg]; + else + return mda->crtcreg; + break; } - return 0xff; + + return 0xFF; } void @@ -118,8 +130,8 @@ mda_recalctimings(mda_t *mda) double _dispontime; double _dispofftime; double disptime; - disptime = mda->crtc[0] + 1; - _dispontime = mda->crtc[1]; + disptime = mda->crtc[MDA_CRTC_HTOTAL] + 1; + _dispontime = mda->crtc[MDA_CRTC_HDISP]; _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; @@ -130,59 +142,141 @@ mda_recalctimings(mda_t *mda) void mda_poll(void *priv) { - mda_t *mda = (mda_t *) priv; - uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; - int drawcursor; - int x; - int c; - int oldvc; + mda_t *mda = (mda_t *) priv; + uint16_t cursoraddr = (mda->crtc[MDA_CRTC_CURSOR_ADDR_LOW] | (mda->crtc[MDA_CRTC_CURSOR_ADDR_HIGH] << 8)) & 0x3fff; + bool drawcursor; + int32_t oldvc; uint8_t chr; uint8_t attr; - int oldsc; - int blink; + int32_t scanline_old; + int32_t blink; VIDEO_MONITOR_PROLOGUE() + if (!mda->linepos) { timer_advance_u64(&mda->timer, mda->dispofftime); - mda->stat |= 1; + mda->status |= 1; mda->linepos = 1; - oldsc = mda->sc; - if ((mda->crtc[8] & 3) == 3) - mda->sc = (mda->sc << 1) & 7; + scanline_old = mda->scanline; + if ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3) + mda->scanline = (mda->scanline << 1) & 7; + if (mda->dispon) { if (mda->displine < mda->firstline) { mda->firstline = mda->displine; video_wait_for_buffer(); } mda->lastline = mda->displine; - for (x = 0; x < mda->crtc[1]; x++) { - chr = mda->vram[(mda->ma << 1) & 0xfff]; - attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; - drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); - blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); - if (mda->sc == 12 && ((attr & 7) == 1)) { - for (c = 0; c < 9; c++) - buffer32->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][1]; - } else { - for (c = 0; c < 8; c++) - buffer32->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr + mda->fontbase][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; - if ((chr & ~0x1f) == 0xc0) - buffer32->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr + mda->fontbase][mda->sc] & 1]; - else - buffer32->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + + for (uint32_t x = 0; x < mda->crtc[MDA_CRTC_HDISP]; x++) { + chr = mda->vram[(mda->memaddr << 1) & 0xfff]; + attr = mda->vram[((mda->memaddr << 1) + 1) & 0xfff]; + drawcursor = ((mda->memaddr == cursoraddr) && mda->cursorvisible && mda->cursoron); + blink = ((mda->blink & 16) && (mda->mode & MDA_MODE_BLINK) && (attr & 0x80) && !drawcursor); + + // Colours that will be used + int32_t color_bg = 0, color_fg = 0; + + // If we are using an RGBI monitor allow colour + if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI + && !(mda->mode & MDA_MODE_BW)) { + color_bg = (attr >> 4) & 0x0F; + color_fg = (attr & 0x0F); + + // turn off bright bg colours in blink mode + if ((mda->mode & MDA_MODE_BLINK) + && (color_bg & 0x8)) + color_bg &= ~(0x8); + + // black-on-non black or white colours forced to white + // grey-on-colours forced to bright white + + bool special_treatment = (color_bg != 0 && color_bg != 7); + + if (color_fg == MDA_COLOR_GREY + && special_treatment) + color_fg = MDA_COLOR_BRIGHT_WHITE; + + if (color_fg == 0 + && special_treatment) + color_fg = MDA_COLOR_GREY; + + // gray is black + if (color_fg == MDA_COLOR_GREY + && (color_bg == MDA_COLOR_GREY || color_bg == MDA_COLOR_BLACK)) + color_fg = MDA_COLOR_BLACK; } - mda->ma++; + + if (mda->scanline == 12 + && ((attr & 7) == 1)) { // underline + for (uint32_t column = 0; column < 9; column++) { + if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI + && !(mda->mode & MDA_MODE_BW)) { + buffer32->line[mda->displine][(x * 9) + column] = CGAPAL_CGA_START + color_fg; + } else + buffer32->line[mda->displine][(x * 9) + column] = mda_attr_to_color_table[attr][blink][1]; + } + } else { // character + for (uint32_t column = 0; column < 8; column++) { + // bg=0, fg=1 + bool is_fg = (fontdatm[chr + mda->fontbase][mda->scanline] & (1 << (column ^ 7))) ? 1 : 0; + + uint32_t font_char = mda_attr_to_color_table[attr][blink][is_fg]; + + if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI + && !(mda->mode & MDA_MODE_BW)) { + if (!is_fg) + font_char = CGAPAL_CGA_START + color_bg; + else + font_char = CGAPAL_CGA_START + color_fg; + } + + buffer32->line[mda->displine][(x * 9) + column] = font_char; + } + + // these characters (C0-DF) have their background extended to their 9th column + if ((chr & ~0x1f) == 0xc0) { + bool is_fg = fontdatm[chr + mda->fontbase][mda->scanline] & 1; + uint32_t final_result = mda_attr_to_color_table[attr][blink][is_fg]; + + if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI + && !(mda->mode & MDA_MODE_BW)) { + if (!is_fg) + final_result = CGAPAL_CGA_START + color_bg; + else + final_result = CGAPAL_CGA_START + color_fg; + } + + buffer32->line[mda->displine][(x * 9) + 8] = final_result; + + } else { + if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI + && !(mda->mode & MDA_MODE_BW)) { + buffer32->line[mda->displine][(x * 9) + 8] = CGAPAL_CGA_START + color_bg; + + } else + buffer32->line[mda->displine][(x * 9) + 8] = mda_attr_to_color_table[attr][blink][0]; + } + } + + mda->memaddr++; + if (drawcursor) { - for (c = 0; c < 9; c++) - buffer32->line[mda->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + for (uint32_t column = 0; column < 9; column++) { + if (mda->monitor_type == MDA_MONITOR_TYPE_RGBI + && !(mda->mode & MDA_MODE_BW)) { + buffer32->line[mda->displine][(x * 9) + column] ^= CGAPAL_CGA_START + color_fg; + } else + buffer32->line[mda->displine][(x * 9) + column] ^= mda_attr_to_color_table[attr][0][1]; + } } } - video_process_8(mda->crtc[1] * 9, mda->displine); + video_process_8(mda->crtc[MDA_CRTC_HDISP] * 9, mda->displine); } - mda->sc = oldsc; - if (mda->vc == mda->crtc[7] && !mda->sc) { - mda->stat |= 8; + mda->scanline = scanline_old; + if (mda->vc == mda->crtc[MDA_CRTC_VSYNC] && !mda->scanline) { + mda->status |= 8; } mda->displine++; if (mda->displine >= 500) @@ -190,53 +284,60 @@ mda_poll(void *priv) } else { timer_advance_u64(&mda->timer, mda->dispontime); if (mda->dispon) - mda->stat &= ~1; + mda->status &= ~1; mda->linepos = 0; + if (mda->vsynctime) { mda->vsynctime--; if (!mda->vsynctime) { - mda->stat &= ~8; + mda->status &= ~8; } } - if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) { - mda->con = 0; + if (mda->scanline == (mda->crtc[MDA_CRTC_CURSOR_END] & 31) + || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 + && mda->scanline == ((mda->crtc[MDA_CRTC_CURSOR_END] & 31) >> 1))) { + mda->cursorvisible = 0; } + if (mda->vadj) { - mda->sc++; - mda->sc &= 31; - mda->ma = mda->maback; + mda->scanline++; + mda->scanline &= 31; + mda->memaddr = mda->memaddr_backup; mda->vadj--; if (!mda->vadj) { - mda->dispon = 1; - mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; - mda->sc = 0; + mda->dispon = 1; + mda->memaddr = mda->memaddr_backup = (mda->crtc[MDA_CRTC_START_ADDR_LOW] | (mda->crtc[MDA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + mda->scanline = 0; } - } else if (mda->sc == mda->crtc[9] || ((mda->crtc[8] & 3) == 3 && mda->sc == (mda->crtc[9] >> 1))) { - mda->maback = mda->ma; - mda->sc = 0; - oldvc = mda->vc; + } else if (mda->scanline == mda->crtc[MDA_CRTC_MAX_SCANLINE_ADDR] + || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 + && mda->scanline == (mda->crtc[MDA_CRTC_MAX_SCANLINE_ADDR] >> 1))) { + mda->memaddr_backup = mda->memaddr; + mda->scanline = 0; + oldvc = mda->vc; mda->vc++; mda->vc &= 127; - if (mda->vc == mda->crtc[6]) + if (mda->vc == mda->crtc[MDA_CRTC_VDISP]) mda->dispon = 0; - if (oldvc == mda->crtc[4]) { + if (oldvc == mda->crtc[MDA_CRTC_VTOTAL]) { mda->vc = 0; - mda->vadj = mda->crtc[5]; + mda->vadj = mda->crtc[MDA_CRTC_VTOTAL_ADJUST]; if (!mda->vadj) mda->dispon = 1; if (!mda->vadj) - mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; - if ((mda->crtc[10] & 0x60) == 0x20) + mda->memaddr = mda->memaddr_backup = (mda->crtc[MDA_CRTC_START_ADDR_LOW] | (mda->crtc[MDA_CRTC_START_ADDR_HIGH] << 8)) & 0x3fff; + if ((mda->crtc[MDA_CRTC_CURSOR_START] & 0x60) == 0x20) mda->cursoron = 0; else mda->cursoron = mda->blink & 16; } - if (mda->vc == mda->crtc[7]) { + + if (mda->vc == mda->crtc[MDA_CRTC_VSYNC]) { mda->dispon = 0; mda->displine = 0; mda->vsynctime = 16; - if (mda->crtc[7]) { - x = mda->crtc[1] * 9; + if (mda->crtc[MDA_CRTC_VSYNC]) { + uint32_t x = mda->crtc[MDA_CRTC_HDISP] * 9; mda->lastline++; if ((x != xsize) || ((mda->lastline - mda->firstline) != ysize) || video_force_resize_get()) { xsize = x; @@ -252,8 +353,8 @@ mda_poll(void *priv) } video_blit_memtoscreen(0, mda->firstline, xsize, ysize); frames++; - video_res_x = mda->crtc[1]; - video_res_y = mda->crtc[6]; + video_res_x = mda->crtc[MDA_CRTC_HDISP]; + video_res_y = mda->crtc[MDA_CRTC_VDISP]; video_bpp = 0; } mda->firstline = 1000; @@ -261,12 +362,15 @@ mda_poll(void *priv) mda->blink++; } } else { - mda->sc++; - mda->sc &= 31; - mda->ma = mda->maback; + mda->scanline++; + mda->scanline &= 31; + mda->memaddr = mda->memaddr_backup; } - if (mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1))) { - mda->con = 1; + + if (mda->scanline == (mda->crtc[MDA_CRTC_CURSOR_START] & 31) + || ((mda->crtc[MDA_CRTC_INTERLACE] & 3) == 3 + && mda->scanline == ((mda->crtc[MDA_CRTC_CURSOR_START] & 31) >> 1))) { + mda->cursorvisible = 1; } } VIDEO_MONITOR_EPILOGUE(); @@ -275,30 +379,32 @@ mda_poll(void *priv) void mda_init(mda_t *mda) { - for (uint16_t c = 0; c < 256; c++) { - mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; - if (c & 8) - mdacols[c][0][1] = 15 + 16; + + for (uint16_t attr = 0; attr < 256; attr++) { + mda_attr_to_color_table[attr][0][0] = mda_attr_to_color_table[attr][1][0] = mda_attr_to_color_table[attr][1][1] = 16; + if (attr & 8) + mda_attr_to_color_table[attr][0][1] = 15 + 16; else - mdacols[c][0][1] = 7 + 16; + mda_attr_to_color_table[attr][0][1] = 7 + 16; } - mdacols[0x70][0][1] = 16; - mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; - mdacols[0xF0][0][1] = 16; - mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; - mdacols[0x78][0][1] = 16 + 7; - mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; - mdacols[0xF8][0][1] = 16 + 7; - mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; - mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; - mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; - mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; - mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + mda_attr_to_color_table[0x70][0][1] = 16; + mda_attr_to_color_table[0x70][0][0] = mda_attr_to_color_table[0x70][1][0] = mda_attr_to_color_table[0x70][1][1] = CGAPAL_CGA_START + 15; + mda_attr_to_color_table[0xF0][0][1] = 16; + mda_attr_to_color_table[0xF0][0][0] = mda_attr_to_color_table[0xF0][1][0] = mda_attr_to_color_table[0xF0][1][1] = CGAPAL_CGA_START + 15; + mda_attr_to_color_table[0x78][0][1] = CGAPAL_CGA_START + 7; + mda_attr_to_color_table[0x78][0][0] = mda_attr_to_color_table[0x78][1][0] = mda_attr_to_color_table[0x78][1][1] = CGAPAL_CGA_START + 15; + mda_attr_to_color_table[0xF8][0][1] = CGAPAL_CGA_START + 7; + mda_attr_to_color_table[0xF8][0][0] = mda_attr_to_color_table[0xF8][1][0] = mda_attr_to_color_table[0xF8][1][1] = CGAPAL_CGA_START + 15; + mda_attr_to_color_table[0x00][0][1] = mda_attr_to_color_table[0x00][1][1] = 16; + mda_attr_to_color_table[0x08][0][1] = mda_attr_to_color_table[0x08][1][1] = 16; + mda_attr_to_color_table[0x80][0][1] = mda_attr_to_color_table[0x80][1][1] = 16; + mda_attr_to_color_table[0x88][0][1] = mda_attr_to_color_table[0x88][1][1] = 16; overscan_x = overscan_y = 0; mda->monitor_index = monitor_index_global; - cga_palette = device_get_config_int("rgb_type") << 1; + mda->monitor_type = device_get_config_int("rgb_type"); + cga_palette = mda->monitor_type << 1; if (cga_palette > 6) { cga_palette = 0; } @@ -323,13 +429,15 @@ mda_standalone_init(UNUSED(const device_t *info)) case 1: loadfont(FONT_IBM_MDA_437_NORDIC_PATH, 0); break; - case 2: loadfont(FONT_KAM_PATH, 0); break; case 3: loadfont(FONT_KAMCL16_PATH, 0); break; + case 4: + loadfont(FONT_TULIP_DGA_PATH, 0); + break; } mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, @@ -353,7 +461,7 @@ mda_standalone_init(UNUSED(const device_t *info)) void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink) { - mdacols[chr][blink][fg] = 16 + cga_ink; + mda_attr_to_color_table[chr][blink][fg] = CGAPAL_CGA_START + cga_ink; } void @@ -383,12 +491,14 @@ static const device_config_t mda_config[] = { .default_int = 0, .file_filter = NULL, .spinner = { 0 }, - .selection = { - { .description = "Default", .value = 0 }, - { .description = "Green", .value = 1 }, - { .description = "Amber", .value = 2 }, - { .description = "Gray", .value = 3 }, - { .description = "" } + .selection = + { + { .description = "Default", .value = MDA_MONITOR_TYPE_DEFAULT }, + { .description = "Green", .value = MDA_MONITOR_TYPE_GREEN }, + { .description = "Amber", .value = MDA_MONITOR_TYPE_AMBER }, + { .description = "Gray", .value = MDA_MONITOR_TYPE_GRAY }, + { .description = "Generic RGBI color monitor", .value = MDA_MONITOR_TYPE_RGBI }, + { .description = "" } }, .bios = { { 0 } } }, @@ -400,12 +510,14 @@ static const device_config_t mda_config[] = { .default_int = 0, .file_filter = NULL, .spinner = { 0 }, - .selection = { - { .description = "US (CP 437)", .value = 0 }, + .selection = + { + { .description = "US (CP 437)", .value = 0 }, { .description = "IBM Nordic (CP 437-Nordic)", .value = 1 }, { .description = "Czech Kamenicky (CP 895) #1", .value = 2 }, { .description = "Czech Kamenicky (CP 895) #2", .value = 3 }, - { .description = "" } + { .description = "Tulip DGA", .value = 4 }, + { .description = "" } }, .bios = { { 0 } } }, @@ -426,3 +538,4 @@ const device_t mda_device = { .force_redraw = NULL, .config = mda_config }; + diff --git a/src/video/vid_mga.c b/src/video/vid_mga.c index 00570bd9f..294e6ce75 100644 --- a/src/video/vid_mga.c +++ b/src/video/vid_mga.c @@ -736,7 +736,7 @@ mystique_out(uint16_t addr, uint8_t val, void *priv) if ((svga->crtcreg & 0x3f) < 0xE || (svga->crtcreg & 0x3f) > 0x10) { if (((svga->crtcreg & 0x3f) == 0xc) || ((svga->crtcreg & 0x3f) == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -768,24 +768,24 @@ mystique_out(uint16_t addr, uint8_t val, void *priv) if (!(mystique->type >= MGA_2164W)) svga->rowoffset <<= 1; - svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | + svga->memaddr_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd]; if ((mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8))) { svga->rowoffset <<= 1; - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; } if (!(mystique->type >= MGA_2164W)) - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; - if (svga->ma_latch != mystique->ma_latch_old) { + if (svga->memaddr_latch != mystique->ma_latch_old) { if (svga->interlace && svga->oddeven) - svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + - (svga->ma_latch << 2) + (svga->rowoffset << 1); + svga->memaddr_backup = (svga->memaddr_backup - (mystique->ma_latch_old << 2)) + + (svga->memaddr_latch << 2) + (svga->rowoffset << 1); else - svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + - (svga->ma_latch << 2); - mystique->ma_latch_old = svga->ma_latch; + svga->memaddr_backup = (svga->memaddr_backup - (mystique->ma_latch_old << 2)) + + (svga->memaddr_latch << 2); + mystique->ma_latch_old = svga->memaddr_latch; } } @@ -895,9 +895,9 @@ mystique_vblank_start(svga_t *svga) mystique_t *mystique = (mystique_t *) svga->priv; if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) { - svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + svga->memaddr_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd]; if (mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8)) - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; } } @@ -984,29 +984,29 @@ mystique_recalctimings(svga_t *svga) svga->lut_map = !!(mystique->xmiscctrl & XMISCCTRL_RAMCS); if (mystique->type >= MGA_1064SG) - svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + svga->memaddr_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 16) | (svga->crtc[0xc] << 8) | svga->crtc[0xd]; if ((mystique->pci_regs[0x41] & (OPTION_INTERLEAVE >> 8))) { svga->rowoffset <<= 1; if (mystique->type >= MGA_1064SG) - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; } if (mystique->type >= MGA_1064SG) { /*Mystique and later, unlike most SVGA cards, allows display start to take effect mid-screen*/ if (!(mystique->type >= MGA_2164W)) - svga->ma_latch <<= 1; - /* Only change maback so the new display start will take effect on the next + svga->memaddr_latch <<= 1; + /* Only change memaddr_backup so the new display start will take effect on the next horizontal retrace. */ - if (svga->ma_latch != mystique->ma_latch_old) { + if (svga->memaddr_latch != mystique->ma_latch_old) { if (svga->interlace && svga->oddeven) - svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + - (svga->ma_latch << 2) + (svga->rowoffset << 1); + svga->memaddr_backup = (svga->memaddr_backup - (mystique->ma_latch_old << 2)) + + (svga->memaddr_latch << 2) + (svga->rowoffset << 1); else - svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + - (svga->ma_latch << 2); - mystique->ma_latch_old = svga->ma_latch; + svga->memaddr_backup = (svga->memaddr_backup - (mystique->ma_latch_old << 2)) + + (svga->memaddr_latch << 2); + mystique->ma_latch_old = svga->memaddr_latch; } if (!(mystique->type >= MGA_2164W)) diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index ce44ef890..3233f9d00 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -30,6 +30,7 @@ #include <86box/vid_svga.h> #include <86box/vid_svga_render.h> #include <86box/plat_unused.h> +#include "cpu.h" #define BIOS_037C_PATH "roms/video/oti/bios.bin" #define BIOS_067_AMA932J_PATH "roms/machines/ama932j/OTI067.BIN" @@ -38,13 +39,13 @@ #define BIOS_077_PATH "roms/video/oti/oti077.vbi" #define BIOS_077_ACER100T_PATH "roms/machines/acer100t/oti077_acer100t.BIN" - enum { - OTI_037C = 0, - OTI_067 = 2, - OTI_067_AMA932J = 3, - OTI_067_M300 = 4, - OTI_077 = 5, + OTI_037C = 0, + OTI_037_PBL300SX = 1, + OTI_067 = 2, + OTI_067_AMA932J = 3, + OTI_067_M300 = 4, + OTI_077 = 5, OTI_077_ACER100T = 6 }; @@ -76,14 +77,15 @@ oti_out(uint16_t addr, uint8_t val, void *priv) uint8_t idx; uint8_t enable; - if (!oti->chip_id && !(oti->enable_register & 1) && (addr != 0x3C3)) + if (!oti->chip_id && !(oti->enable_register & 1) && (addr != 0x3c3)) return; - if ((((addr & 0xFFF0) == 0x3D0 || (addr & 0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) + if (((((addr & 0xfff0) == 0x3d0) || ((addr & 0xfff0) == 0x3b0)) && (addr < 0x3de)) && + !(svga->miscout & 1)) addr ^= 0x60; switch (addr) { - case 0x3C3: + case 0x3c3: if (!oti->chip_id) { oti->enable_register = val & 1; return; @@ -95,20 +97,20 @@ oti_out(uint16_t addr, uint8_t val, void *priv) case 0x3c7: case 0x3c8: case 0x3c9: - if (oti->chip_id == OTI_077 || oti->chip_id == OTI_077_ACER100T) + if ((oti->chip_id == OTI_077) || (oti->chip_id == OTI_077_ACER100T)) sc1148x_ramdac_out(addr, 0, val, svga->ramdac, svga); else svga_out(addr, val, svga); return; - case 0x3D4: + case 0x3d4: if (oti->chip_id) svga->crtcreg = val & 0x3f; else svga->crtcreg = val; /* FIXME: The BIOS wants to set the test bit? */ return; - case 0x3D5: + case 0x3d5: if (oti->chip_id && (svga->crtcreg & 0x20)) return; idx = svga->crtcreg; @@ -124,7 +126,8 @@ oti_out(uint16_t addr, uint8_t val, void *priv) if ((idx < 0x0e) || (idx > 0x10)) { if (idx == 0x0c || idx == 0x0d) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -133,14 +136,14 @@ oti_out(uint16_t addr, uint8_t val, void *priv) } break; - case 0x3DE: + case 0x3de: if (oti->chip_id) oti->index = val & 0x1f; else oti->index = val; return; - case 0x3DF: + case 0x3df: idx = oti->index; if (!oti->chip_id) idx &= 0x1f; @@ -223,14 +226,14 @@ oti_in(uint16_t addr, void *priv) addr ^= 0x60; switch (addr) { - case 0x3C2: + case 0x3c2: if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) temp = 0; else temp = 0x10; break; - case 0x3C3: + case 0x3c3: if (oti->chip_id) temp = svga_in(addr, svga); else @@ -248,11 +251,11 @@ oti_in(uint16_t addr, void *priv) case 0x3CF: return svga->gdcreg[svga->gdcaddr & 0xf]; - case 0x3D4: + case 0x3d4: temp = svga->crtcreg; break; - case 0x3D5: + case 0x3d5: if (oti->chip_id) { if (svga->crtcreg & 0x20) temp = 0xff; @@ -262,17 +265,19 @@ oti_in(uint16_t addr, void *priv) temp = svga->crtc[svga->crtcreg & 0x1f]; break; - case 0x3DA: + case 0x3da: if (oti->chip_id) { temp = svga_in(addr, svga); break; } svga->attrff = 0; - /*The OTI-037C BIOS waits for bits 0 and 3 in 0x3da to go low, then reads 0x3da again - and expects the diagnostic bits to equal the current border colour. As I understand - it, the 0x3da active enable status does not include the border time, so this may be - an area where OTI-037C is not entirely VGA compatible.*/ + /* + The OTI-037C BIOS waits for bits 0 and 3 in 0x3da to go low, then reads 0x3da again + and expects the diagnostic bits to equal the current border colour. As I understand + it, the 0x3da active enable status does not include the border time, so this may be + an area where OTI-037C is not entirely VGA compatible. + */ svga->cgastat &= ~0x30; /* copy color diagnostic info from the overscan color register */ switch (svga->attrregs[0x12] & 0x30) { @@ -307,13 +312,13 @@ oti_in(uint16_t addr, void *priv) temp = svga->cgastat; break; - case 0x3DE: + case 0x3de: temp = oti->index; if (oti->chip_id) temp |= (oti->chip_id << 5); break; - case 0x3DF: + case 0x3df: idx = oti->index; if (!oti->chip_id) idx &= 0x1f; @@ -393,9 +398,9 @@ oti_recalctimings(svga_t *svga) if (oti->chip_id > 0) { if (oti->regs[0x14] & 0x08) - svga->ma_latch |= 0x10000; + svga->memaddr_latch |= 0x10000; if (oti->regs[0x16] & 0x08) - svga->ma_latch |= 0x20000; + svga->memaddr_latch |= 0x20000; if (oti->regs[0x14] & 0x01) svga->vtotal += 0x400; @@ -441,6 +446,13 @@ oti_init(const device_t *info) #endif break; + case OTI_037_PBL300SX: + romfn = NULL; + oti->chip_id = 0; + oti->vram_size = 256; + oti->regs[0] = 0x08; /* FIXME: The BIOS wants to read this at index 0? This index is undocumented. */ + break; + case OTI_067_AMA932J: romfn = BIOS_067_AMA932J_PATH; oti->chip_id = 2; @@ -478,26 +490,25 @@ oti_init(const device_t *info) break; } - if (romfn != NULL) { + if (romfn != NULL) rom_init(&oti->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - } oti->vram_mask = (oti->vram_size << 10) - 1; - if (oti->chip_id == OTI_077_ACER100T){ - /* josephillips: Required to show all BIOS - information on Acer 100T only + if (oti->chip_id == OTI_077_ACER100T) { + /* + josephillips: Required to show all BIOS + information on Acer 100T only */ - video_inform(0x1,&timing_oti); - }else{ + video_inform(0x1, &timing_oti); + } else video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_oti); - } svga_init(info, &oti->svga, oti, oti->vram_size << 10, oti_recalctimings, oti_in, oti_out, NULL, NULL); - if (oti->chip_id == OTI_077 || oti->chip_id == OTI_077_ACER100T) + if ((oti->chip_id == OTI_077) || (oti->chip_id == OTI_077_ACER100T)) oti->svga.ramdac = device_add(&sc11487_ramdac_device); /*Actually a 82c487, probably a clone.*/ io_sethandler(0x03c0, 32, @@ -662,6 +673,20 @@ const device_t oti037c_device = { .config = NULL }; +const device_t oti037_pbl300sx_device = { + .name = "Oak OTI-037 (Packard Bell Legend 300SX)", + .internal_name = "oti037_pbl300sx", + .flags = DEVICE_ISA, + .local = 1, + .init = oti_init, + .close = oti_close, + .reset = NULL, + .available = NULL, + .speed_changed = oti_speed_changed, + .force_redraw = oti_force_redraw, + .config = NULL +}; + const device_t oti067_device = { .name = "Oak OTI-067", .internal_name = "oti067", @@ -676,20 +701,6 @@ const device_t oti067_device = { .config = oti067_config }; -const device_t oti067_m300_device = { - .name = "Oak OTI-067 (Olivetti M300-08/15)", - .internal_name = "oti067_m300", - .flags = DEVICE_ISA, - .local = 4, - .init = oti_init, - .close = oti_close, - .reset = NULL, - .available = oti067_m300_available, - .speed_changed = oti_speed_changed, - .force_redraw = oti_force_redraw, - .config = oti067_config -}; - const device_t oti067_ama932j_device = { .name = "Oak OTI-067 (AMA-932J)", .internal_name = "oti067_ama932j", @@ -704,21 +715,20 @@ const device_t oti067_ama932j_device = { .config = oti067_ama932j_config }; -const device_t oti077_acer100t_device = { - .name = "Oak OTI-077 (Acer 100T)", - .internal_name = "oti077_acer100t", +const device_t oti067_m300_device = { + .name = "Oak OTI-067 (Olivetti M300-08/15)", + .internal_name = "oti067_m300", .flags = DEVICE_ISA, - .local = 6, + .local = 4, .init = oti_init, .close = oti_close, .reset = NULL, - .available = oti077_acer100t_available, + .available = oti067_m300_available, .speed_changed = oti_speed_changed, .force_redraw = oti_force_redraw, - .config = oti077_acer100t_config + .config = oti067_config }; - const device_t oti077_device = { .name = "Oak OTI-077", .internal_name = "oti077", @@ -732,3 +742,17 @@ const device_t oti077_device = { .force_redraw = oti_force_redraw, .config = oti077_config }; + +const device_t oti077_acer100t_device = { + .name = "Oak OTI-077 (Acer 100T)", + .internal_name = "oti077_acer100t", + .flags = DEVICE_ISA, + .local = 6, + .init = oti_init, + .close = oti_close, + .reset = NULL, + .available = oti077_acer100t_available, + .speed_changed = oti_speed_changed, + .force_redraw = oti_force_redraw, + .config = oti077_acer100t_config +}; diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index da8bb9aa6..a9b0c65a5 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -245,7 +245,7 @@ paradise_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); diff --git a/src/video/vid_pcjr.c b/src/video/vid_pcjr.c new file mode 100644 index 000000000..2b3eb730a --- /dev/null +++ b/src/video/vid_pcjr.c @@ -0,0 +1,706 @@ +/* + * 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. + * + * IBM PCjr video subsystem emulation + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Connor Hyde / starfrost + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2025 starfrost + */ + +#include +#include +#include +#include +#include +#include <86box/86box.h> +#include <86box/io.h> +#include <86box/timer.h> +#include <86box/mem.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/video.h> +#include <86box/vid_cga.h> +#include <86box/vid_cga_comp.h> + +#include <86box/m_pcjr.h> + +static video_timings_t timing_dram = { VIDEO_BUS, 0, 0, 0, 0, 0, 0 }; /*No additional waitstates*/ + +static uint8_t crtcmask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void +recalc_address(pcjr_t *pcjr) +{ + uint8_t masked_memctrl = pcjr->memctrl; + + /* According to the Technical Reference, bits 2 and 5 are + ignored if there is only 64k of RAM and there are only + 4 pages. */ + if (mem_size < 128) + masked_memctrl &= ~0x24; + + if ((pcjr->memctrl & 0xc0) == 0xc0) { + pcjr->vram = &ram[(masked_memctrl & 0x06) << 14]; + pcjr->b8000 = &ram[(masked_memctrl & 0x30) << 11]; + } else { + pcjr->vram = &ram[(masked_memctrl & 0x07) << 14]; + pcjr->b8000 = &ram[(masked_memctrl & 0x38) << 11]; + } +} + +void +pcjr_recalc_timings(pcjr_t *pcjr) +{ + double _dispontime; + double _dispofftime; + double disptime; + + if (pcjr->array[0] & 1) { + disptime = pcjr->crtc[0] + 1; + _dispontime = pcjr->crtc[1]; + } else { + disptime = (pcjr->crtc[0] + 1) << 1; + _dispontime = pcjr->crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + pcjr->dispontime = (uint64_t) (_dispontime); + pcjr->dispofftime = (uint64_t) (_dispofftime); +} + +static int +vid_get_h_overscan_size(pcjr_t *pcjr) +{ + int ret; + + if (pcjr->array[0] & 1) + ret = 128; + else + ret = 256; + + return ret; +} + +static void +vid_out(uint16_t addr, uint8_t val, void *priv) +{ + pcjr_t *pcjr = (pcjr_t *) priv; + uint8_t old; + + switch (addr) { + case 0x3d0: + case 0x3d2: + case 0x3d4: + case 0x3d6: + pcjr->crtcreg = val & 0x1f; + return; + + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + old = pcjr->crtc[pcjr->crtcreg]; + pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; + if (pcjr->crtcreg == 2) + overscan_x = vid_get_h_overscan_size(pcjr); + if (old != val) { + if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) { + pcjr->fullchange = changeframecount; + pcjr_recalc_timings(pcjr); + } + } + return; + + case 0x3da: + if (!pcjr->array_ff) + pcjr->array_index = val & 0x1f; + else { + if (pcjr->array_index & 0x10) + val &= 0x0f; + pcjr->array[pcjr->array_index & 0x1f] = val; + if (!(pcjr->array_index & 0x1f)) + update_cga16_color(val); + } + pcjr->array_ff = !pcjr->array_ff; + break; + + case 0x3df: + pcjr->memctrl = val; + pcjr->pa = val; /* The PCjr BIOS expects the value written to 3DF to + then be readable from port 60, others it errors out + with only 64k RAM set (but somehow, still works with + 128k or more RAM). */ + pcjr->addr_mode = val >> 6; + recalc_address(pcjr); + break; + + default: + break; + } +} + +static uint8_t +vid_in(uint16_t addr, void *priv) +{ + pcjr_t *pcjr = (pcjr_t *) priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3d0: + case 0x3d2: + case 0x3d4: + case 0x3d6: + ret = pcjr->crtcreg; + break; + + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + ret = pcjr->crtc[pcjr->crtcreg]; + break; + + case 0x3da: + pcjr->array_ff = 0; + pcjr->status ^= 0x10; + ret = pcjr->status; + break; + + default: + break; + } + + return ret; +} + +static void +vid_write(uint32_t addr, uint8_t val, void *priv) +{ + pcjr_t *pcjr = (pcjr_t *) priv; + + if (pcjr->memctrl == -1) + return; + + pcjr->b8000[addr & 0x3fff] = val; +} + +static uint8_t +vid_read(uint32_t addr, void *priv) +{ + const pcjr_t *pcjr = (pcjr_t *) priv; + + if (pcjr->memctrl == -1) + return 0xff; + + return (pcjr->b8000[addr & 0x3fff]); +} + +static int +vid_get_h_overscan_delta(pcjr_t *pcjr) +{ + int def; + int coef; + int ret; + + switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { + case 0x13: /*320x200x16*/ + def = 0x56; + coef = 8; + break; + case 0x12: /*160x200x16*/ + def = 0x2c; /* I'm going to assume a datasheet erratum here. */ + coef = 16; + break; + case 0x03: /*640x200x4*/ + def = 0x56; + coef = 8; + break; + case 0x01: /*80 column text*/ + def = 0x5a; + coef = 8; + break; + case 0x00: /*40 column text*/ + default: + def = 0x2c; + coef = 16; + break; + case 0x02: /*320x200x4*/ + def = 0x2b; + coef = 16; + break; + case 0x102: /*640x200x2*/ + def = 0x2b; + coef = 16; + break; + } + + ret = pcjr->crtc[0x02] - def; + + if (ret < -8) + ret = -8; + + if (ret > 8) + ret = 8; + + return ret * coef; +} + +static void +vid_blit_h_overscan(pcjr_t *pcjr) +{ + int cols = (pcjr->array[2] & 0xf) + 16;; + int y0 = pcjr->firstline << 1; + int y = (pcjr->lastline << 1) + 16; + int ho_s = vid_get_h_overscan_size(pcjr); + int i; + int x; + + if (pcjr->array[0] & 1) + x = (pcjr->crtc[1] << 3) + ho_s; + else + x = (pcjr->crtc[1] << 4) + ho_s; + + for (i = 0; i < 16; i++) { + hline(buffer32, 0, y0 + i, x, cols); + hline(buffer32, 0, y + i, x, cols); + + if (pcjr->composite) { + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[y0 + i]); + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[y + i]); + } else { + video_process_8(x, y0 + i); + video_process_8(x, y + i); + } + } +} + +static void +vid_poll(void *priv) +{ + pcjr_t *pcjr = (pcjr_t *) priv; + uint16_t cursoraddr = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x; + int xs_temp; + int ys_temp; + int oldvc; + uint8_t chr; + uint8_t attr; + uint16_t dat; + int cols[4]; + int scanline_old; + int l = (pcjr->displine << 1) + 16; + int ho_s = vid_get_h_overscan_size(pcjr); + int ho_d = vid_get_h_overscan_delta(pcjr) + (ho_s / 2); + + if (!pcjr->linepos) { + timer_advance_u64(&pcjr->timer, pcjr->dispofftime); + pcjr->status &= ~1; + pcjr->linepos = 1; + scanline_old = pcjr->scanline; + if ((pcjr->crtc[8] & 3) == 3) + pcjr->scanline = (pcjr->scanline << 1) & 7; + if (pcjr->dispon) { + uint16_t offset = 0; + uint16_t mask = 0x1fff; + + if (pcjr->displine < pcjr->firstline) { + pcjr->firstline = pcjr->displine; + video_wait_for_buffer(); + } + pcjr->lastline = pcjr->displine; + cols[0] = (pcjr->array[2] & 0xf) + 16; + + if (pcjr->array[0] & 1) { + hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, cols[0]); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, cols[0]); + } else { + hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, cols[0]); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, cols[0]); + } + + switch (pcjr->addr_mode) { + case 0: /*Alpha*/ + offset = 0; + mask = 0x3fff; + break; + case 1: /*Low resolution graphics*/ + offset = (pcjr->scanline & 1) * 0x2000; + break; + case 3: /*High resolution graphics*/ + offset = (pcjr->scanline & 3) * 0x2000; + break; + default: + break; + } + switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { + case 0x13: /*320x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 3) + ho_d; + dat = (pcjr->vram[((pcjr->memaddr << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->memaddr << 1) & mask) + offset + 1]; + pcjr->memaddr++; + buffer32->line[l][ef_x] = buffer32->line[l][ef_x + 1] = + buffer32->line[l + 1][ef_x] = buffer32->line[l + 1][ef_x + 1] = + pcjr->array[((dat >> 12) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 2] = buffer32->line[l][ef_x + 3] = + buffer32->line[l + 1][ef_x + 2] = buffer32->line[l + 1][ef_x + 3] = + pcjr->array[((dat >> 8) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 4] = buffer32->line[l][ef_x + 5] = + buffer32->line[l + 1][ef_x + 4] = buffer32->line[l + 1][ef_x + 5] = + pcjr->array[((dat >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 6] = buffer32->line[l][ef_x + 7] = + buffer32->line[l + 1][ef_x + 6] = buffer32->line[l + 1][ef_x + 7] = + pcjr->array[(dat & pcjr->array[1] & 0x0f) + 16] + 16; + } + break; + case 0x12: /*160x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 4) + ho_d; + dat = (pcjr->vram[((pcjr->memaddr << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->memaddr << 1) & mask) + offset + 1]; + pcjr->memaddr++; + buffer32->line[l][ef_x] = buffer32->line[l][ef_x + 1] = + buffer32->line[l][ef_x + 2] = buffer32->line[l][ef_x + 3] = + buffer32->line[l + 1][ef_x] = buffer32->line[l + 1][ef_x + 1] = + buffer32->line[l + 1][ef_x + 2] = buffer32->line[l + 1][ef_x + 3] = + pcjr->array[((dat >> 12) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 4] = buffer32->line[l][ef_x + 5] = + buffer32->line[l][ef_x + 6] = buffer32->line[l][ef_x + 7] = + buffer32->line[l + 1][ef_x + 4] = buffer32->line[l + 1][ef_x + 5] = + buffer32->line[l + 1][ef_x + 6] = buffer32->line[l + 1][ef_x + 7] = + pcjr->array[((dat >> 8) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 8] = buffer32->line[l][ef_x + 9] = + buffer32->line[l][ef_x + 10] = buffer32->line[l][ef_x + 11] = + buffer32->line[l + 1][ef_x + 8] = buffer32->line[l + 1][ef_x + 9] = + buffer32->line[l + 1][ef_x + 10] = buffer32->line[l + 1][ef_x + 11] = + pcjr->array[((dat >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; + buffer32->line[l][ef_x + 12] = buffer32->line[l][ef_x + 13] = + buffer32->line[l][ef_x + 14] = buffer32->line[l][ef_x + 15] = + buffer32->line[l + 1][ef_x + 12] = buffer32->line[l + 1][ef_x + 13] = + buffer32->line[l + 1][ef_x + 14] = buffer32->line[l + 1][ef_x + 15] = + pcjr->array[(dat & pcjr->array[1] & 0x0f) + 16] + 16; + } + break; + case 0x03: /*640x200x4*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 3) + ho_d; + dat = (pcjr->vram[((pcjr->memaddr << 1) & mask) + offset + 1] << 8) | + pcjr->vram[((pcjr->memaddr << 1) & mask) + offset]; + pcjr->memaddr++; + for (uint8_t c = 0; c < 8; c++) { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer32->line[l][ef_x + c] = buffer32->line[l + 1][ef_x + c] = + pcjr->array[(chr & pcjr->array[1] & 0x0f) + 16] + 16; + dat <<= 1; + } + } + break; + case 0x01: /*80 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 3) + ho_d; + chr = pcjr->vram[((pcjr->memaddr << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->memaddr << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->memaddr == cursoraddr) && pcjr->cursorvisible && pcjr->cursoron); + if (pcjr->array[3] & 4) { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1] & 0x0f) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; + } + if (pcjr->scanline & 8) + for (uint8_t c = 0; c < 8; c++) + buffer32->line[l][ef_x + c] = + buffer32->line[l + 1][ef_x + c] = cols[0]; + else + for (uint8_t c = 0; c < 8; c++) + buffer32->line[l][ef_x + c] = + buffer32->line[l + 1][ef_x + c] = + cols[(fontdat[chr][pcjr->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + if (drawcursor) + for (uint8_t c = 0; c < 8; c++) { + buffer32->line[l][ef_x + c] ^= 15; + buffer32->line[l + 1][ef_x + c] ^= 15; + } + pcjr->memaddr++; + } + break; + case 0x00: /*40 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 4) + ho_d; + chr = pcjr->vram[((pcjr->memaddr << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->memaddr << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->memaddr == cursoraddr) && pcjr->cursorvisible && pcjr->cursoron); + if (pcjr->array[3] & 4) { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1] & 0x0f) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1] & 0x0f) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1] & 0x0f) + 16] + 16; + } + pcjr->memaddr++; + if (pcjr->scanline & 8) + for (uint8_t c = 0; c < 8; c++) + buffer32->line[l][ef_x + (c << 1)] = + buffer32->line[l][ef_x + (c << 1) + 1] = + buffer32->line[l + 1][ef_x + (c << 1)] = + buffer32->line[l + 1][ef_x + (c << 1) + 1] = cols[0]; + else + for (uint8_t c = 0; c < 8; c++) + buffer32->line[l][ef_x + (c << 1)] = + buffer32->line[l][ef_x + (c << 1) + 1] = + buffer32->line[l + 1][ef_x + (c << 1)] = + buffer32->line[l + 1][ef_x + (c << 1) + 1] = + cols[(fontdat[chr][pcjr->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + if (drawcursor) + for (uint8_t c = 0; c < 16; c++) { + buffer32->line[l][ef_x + c] ^= 15; + buffer32->line[l + 1][ef_x + c] ^= 15; + } + } + break; + case 0x02: /*320x200x4*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + cols[2] = pcjr->array[2 + 16] + 16; + cols[3] = pcjr->array[3 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 4) + ho_d; + dat = (pcjr->vram[((pcjr->memaddr << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->memaddr << 1) & mask) + offset + 1]; + pcjr->memaddr++; + for (uint8_t c = 0; c < 8; c++) { + buffer32->line[l][ef_x + (c << 1)] = + buffer32->line[l][ef_x + (c << 1) + 1] = + buffer32->line[l + 1][ef_x + (c << 1)] = + buffer32->line[l + 1][ef_x + (c << 1) + 1] = cols[dat >> 14]; + dat <<= 2; + } + } + break; + case 0x102: /*640x200x2*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) { + int ef_x = (x << 4) + ho_d; + dat = (pcjr->vram[((pcjr->memaddr << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->memaddr << 1) & mask) + offset + 1]; + pcjr->memaddr++; + for (uint8_t c = 0; c < 16; c++) { + buffer32->line[l][ef_x + c] = buffer32->line[l + 1][ef_x + c] = + cols[dat >> 15]; + dat <<= 1; + } + } + break; + + default: + break; + } + } else { + if (pcjr->array[3] & 4) { + if (pcjr->array[0] & 1) { + hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, (pcjr->array[2] & 0xf) + 16); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, (pcjr->array[2] & 0xf) + 16); + } else { + hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, (pcjr->array[2] & 0xf) + 16); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, (pcjr->array[2] & 0xf) + 16); + } + } else { + cols[0] = pcjr->array[0 + 16] + 16; + if (pcjr->array[0] & 1) { + hline(buffer32, 0, l, (pcjr->crtc[1] << 3) + ho_s, cols[0]); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 3) + ho_s, cols[0]); + } else { + hline(buffer32, 0, l, (pcjr->crtc[1] << 4) + ho_s, cols[0]); + hline(buffer32, 0, l + 1, (pcjr->crtc[1] << 4) + ho_s, cols[0]); + } + } + } + if (pcjr->array[0] & 1) + x = (pcjr->crtc[1] << 3) + ho_s; + else + x = (pcjr->crtc[1] << 4) + ho_s; + if (pcjr->composite) { + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[l]); + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[l + 1]); + } else { + video_process_8(x, l); + video_process_8(x, l + 1); + } + pcjr->scanline = scanline_old; + if (pcjr->vc == pcjr->crtc[7] && !pcjr->scanline) { + pcjr->status |= 8; + } + pcjr->displine++; + if (pcjr->displine >= 360) + pcjr->displine = 0; + } else { + timer_advance_u64(&pcjr->timer, pcjr->dispontime); + if (pcjr->dispon) + pcjr->status |= 1; + pcjr->linepos = 0; + if (pcjr->vsynctime) { + pcjr->vsynctime--; + if (!pcjr->vsynctime) { + pcjr->status &= ~8; + } + } + if (pcjr->scanline == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->scanline == ((pcjr->crtc[11] & 31) >> 1))) { + pcjr->cursorvisible = 0; + } + if (pcjr->vadj) { + pcjr->scanline++; + pcjr->scanline &= 31; + pcjr->memaddr = pcjr->memaddr_backup; + pcjr->vadj--; + if (!pcjr->vadj) { + pcjr->dispon = 1; + pcjr->memaddr = pcjr->memaddr_backup = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + pcjr->scanline = 0; + } + } else if (pcjr->scanline == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->scanline == (pcjr->crtc[9] >> 1))) { + pcjr->memaddr_backup = pcjr->memaddr; + pcjr->scanline = 0; + oldvc = pcjr->vc; + pcjr->vc++; + pcjr->vc &= 127; + if (pcjr->vc == pcjr->crtc[6]) + pcjr->dispon = 0; + if (oldvc == pcjr->crtc[4]) { + pcjr->vc = 0; + pcjr->vadj = pcjr->crtc[5]; + if (!pcjr->vadj) + pcjr->dispon = 1; + if (!pcjr->vadj) + pcjr->memaddr = pcjr->memaddr_backup = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + if ((pcjr->crtc[10] & 0x60) == 0x20) + pcjr->cursoron = 0; + else + pcjr->cursoron = pcjr->blink & 16; + } + if (pcjr->vc == pcjr->crtc[7]) { + pcjr->dispon = 0; + pcjr->displine = 0; + pcjr->vsynctime = 16; + picint(1 << 5); + if (pcjr->crtc[7]) { + if (pcjr->array[0] & 1) + x = (pcjr->crtc[1] << 3) + ho_s; + else + x = (pcjr->crtc[1] << 4) + ho_s; + pcjr->lastline++; + + xs_temp = x; + ys_temp = (pcjr->lastline - pcjr->firstline) << 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + int actual_ys = ys_temp; + + if (xs_temp < 64) + xs_temp = 656; + if (ys_temp < 32) + ys_temp = 400; + if (!enable_overscan) + xs_temp -= ho_s; + + if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + xsize = xs_temp; + ysize = ys_temp; + + set_screen_size(xsize, ysize + (enable_overscan ? 32 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + vid_blit_h_overscan(pcjr); + + if (enable_overscan) { + video_blit_memtoscreen(0, pcjr->firstline << 1, + xsize, actual_ys + 32); + } else if (pcjr->apply_hd) { + video_blit_memtoscreen(ho_s / 2, (pcjr->firstline << 1) + 16, + xsize, actual_ys); + } else { + video_blit_memtoscreen(ho_d, (pcjr->firstline << 1) + 16, + xsize, actual_ys); + } + } + + frames++; + video_res_x = xsize; + video_res_y = ysize; + } + pcjr->firstline = 1000; + pcjr->lastline = 0; + pcjr->blink++; + } + } else { + pcjr->scanline++; + pcjr->scanline &= 31; + pcjr->memaddr = pcjr->memaddr_backup; + } + if (pcjr->scanline == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->scanline == ((pcjr->crtc[10] & 31) >> 1))) + pcjr->cursorvisible = 1; + } +} + + +void +pcjr_vid_init(pcjr_t *pcjr) +{ + int display_type; + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); + + pcjr->memctrl = -1; + if (mem_size < 128) + pcjr->memctrl &= ~0x24; + + display_type = device_get_config_int("display_type"); + pcjr->composite = (display_type == PCJR_COMPOSITE); + pcjr->apply_hd = device_get_config_int("apply_hd"); + overscan_x = 256; + overscan_y = 32; + + mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, + vid_read, NULL, NULL, + vid_write, NULL, NULL, NULL, 0, pcjr); + io_sethandler(0x03d0, 16, + vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); + timer_add(&pcjr->timer, vid_poll, pcjr, 1); + + if (pcjr->composite) + cga_palette = 0; + else + cga_palette = (display_type << 1); + cgapal_rebuild(); +} diff --git a/src/video/vid_pgc.c b/src/video/vid_pgc.c index 5cb35dc4e..63126955c 100644 --- a/src/video/vid_pgc.c +++ b/src/video/vid_pgc.c @@ -2342,23 +2342,23 @@ pgc_cga_text(pgc_t *dev, int w) int drawcursor = 0; uint32_t cols[2]; int pitch = (dev->mapram[0x3e9] + 1) * 2; - uint16_t sc = (dev->displine & 0x0f) % pitch; - uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; - uint16_t ca = (dev->mapram[0x3ef] | (dev->mapram[0x3ee] << 8)) & 0x3fff; + uint16_t scanline = (dev->displine & 0x0f) % pitch; + uint16_t memaddr = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint16_t cursoraddr = (dev->mapram[0x3ef] | (dev->mapram[0x3ee] << 8)) & 0x3fff; const uint8_t *addr; uint32_t val; int cw = (w == 80) ? 8 : 16; - addr = &dev->cga_vram[((ma + ((dev->displine / pitch) * w)) * 2) & 0x3ffe]; - ma += (dev->displine / pitch) * w; + addr = &dev->cga_vram[((memaddr + ((dev->displine / pitch) * w)) * 2) & 0x3ffe]; + memaddr += (dev->displine / pitch) * w; for (int x = 0; x < w; x++) { chr = *addr++; attr = *addr++; /* Cursor enabled? */ - if (ma == ca && (dev->cgablink & 8) && (dev->mapram[0x3ea] & 0x60) != 0x20) { - drawcursor = ((dev->mapram[0x3ea] & 0x1f) <= (sc >> 1)) && ((dev->mapram[0x3eb] & 0x1f) >= (sc >> 1)); + if (memaddr == cursoraddr && (dev->cgablink & 8) && (dev->mapram[0x3ea] & 0x60) != 0x20) { + drawcursor = ((dev->mapram[0x3ea] & 0x1f) <= (scanline >> 1)) && ((dev->mapram[0x3eb] & 0x1f) >= (scanline >> 1)); } else drawcursor = 0; @@ -2374,9 +2374,9 @@ pgc_cga_text(pgc_t *dev, int w) for (int c = 0; c < cw; c++) { if (drawcursor) - val = cols[(fontdatm[chr + dev->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; + val = cols[(fontdatm[chr + dev->fontbase][scanline] & (1 << (c ^ 7))) ? 1 : 0] ^ 0x0f; else - val = cols[(fontdatm[chr + dev->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; + val = cols[(fontdatm[chr + dev->fontbase][scanline] & (1 << (c ^ 7))) ? 1 : 0]; if (cw == 8) /* 80x25 CGA text screen. */ buffer32->line[dev->displine][(x * cw) + c] = val; else { /* 40x25 CGA text screen. */ @@ -2385,7 +2385,7 @@ pgc_cga_text(pgc_t *dev, int w) } } - ma++; + memaddr++; } } @@ -2395,7 +2395,7 @@ pgc_cga_gfx40(pgc_t *dev) { uint32_t cols[4]; int col; - uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint16_t memaddr = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; const uint8_t *addr; uint16_t dat; @@ -2422,9 +2422,9 @@ pgc_cga_gfx40(pgc_t *dev) } for (uint8_t x = 0; x < 40; x++) { - addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; + addr = &dev->cga_vram[(memaddr + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; dat = (addr[0] << 8) | addr[1]; - dev->ma++; + dev->memaddr++; for (uint8_t c = 0; c < 8; c++) { buffer32->line[dev->displine][(x << 4) + (c << 1)] = buffer32->line[dev->displine][(x << 4) + (c << 1) + 1] = cols[dat >> 14]; dat <<= 2; @@ -2437,7 +2437,7 @@ void pgc_cga_gfx80(pgc_t *dev) { uint32_t cols[2]; - uint16_t ma = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; + uint16_t memaddr = (dev->mapram[0x3ed] | (dev->mapram[0x3ec] << 8)) & 0x3fff; const uint8_t *addr; uint16_t dat; @@ -2445,9 +2445,9 @@ pgc_cga_gfx80(pgc_t *dev) cols[1] = (dev->mapram[0x3d9] & 15) + 16; for (uint8_t x = 0; x < 40; x++) { - addr = &dev->cga_vram[(ma + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; + addr = &dev->cga_vram[(memaddr + 2 * x + 80 * (dev->displine >> 2) + 0x2000 * ((dev->displine >> 1) & 1)) & 0x3fff]; dat = (addr[0] << 8) | addr[1]; - dev->ma++; + dev->memaddr++; for (uint8_t c = 0; c < 16; c++) { buffer32->line[dev->displine][(x << 4) + c] = cols[dat >> 15]; dat <<= 1; diff --git a/src/video/vid_ps55da2.c b/src/video/vid_ps55da2.c index 567d60347..938e4bf6b 100644 --- a/src/video/vid_ps55da2.c +++ b/src/video/vid_ps55da2.c @@ -349,7 +349,7 @@ typedef struct da2_t { int lowres; int rowcount; double clock; - uint32_t ma_latch, ca_adj; + uint32_t memaddr_latch, ca_adj; uint64_t dispontime, dispofftime; pc_timer_t timer; @@ -358,11 +358,11 @@ typedef struct da2_t { int dispon; int hdisp_on; - uint32_t ma, maback, ca; + uint32_t memaddr, memaddr_backup, cursoraddr; int vc; - int sc; + int scanline; int linepos, vslines, linecountff; - int con, cursoron, blink, blinkconf; + int cursorvisible, cursoron, blink, blinkconf; int scrollcache; int char_width; @@ -1960,10 +1960,10 @@ da2_render_text(da2_t *da2) uint32_t chr_dbcs; int chr_wide = 0; int colormode = ((da2->attrc[LV_PAS_STATUS_CNTRL] & 0x80) == 0x80); - // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + // da2_log("\nda2ma: %x, da2sc: %x\n", da2->memaddr, da2->scanline); for (x = 0; x < da2->hdisp; x += 13) { - chr = da2->cram[(da2->ma) & DA2_MASK_CRAM]; - attr = da2->cram[(da2->ma + 1) & DA2_MASK_CRAM]; + chr = da2->cram[(da2->memaddr) & DA2_MASK_CRAM]; + attr = da2->cram[(da2->memaddr + 1) & DA2_MASK_CRAM]; // if(chr!=0x20) da2_log("chr: %x, attr: %x ", chr, attr); if (colormode) /* IO 3E8h, Index 1Dh */ { /* --Parse attribute byte in color mode-- */ @@ -2003,11 +2003,11 @@ da2_render_text(da2_t *da2) /* Stay drawing If the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ - chr_dbcs = da2->cram[(da2->ma + 2) & DA2_MASK_CRAM]; + chr_dbcs = da2->cram[(da2->memaddr + 2) & DA2_MASK_CRAM]; chr_dbcs <<= 8; chr_dbcs |= chr; /* Get the font pattern */ - uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->scanline, da2); /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; @@ -2020,10 +2020,10 @@ da2_render_text(da2_t *da2) fontbase = DA2_GAIJIRAM_SBEX; else fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ + uint16_t font = da2->mmio.ram[fontbase + chr * 0x40 + da2->scanline * 2]; /* w13xh29 font */ font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1]; /* w13xh29 font */ - // if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->scanline * 2 + 1]; /* w13xh29 font */ + // if(chr!=0x20) da2_log("memaddr: %x, scanline: %x, chr: %x, font: %x ", da2->memaddr, da2->scanline, chr, font); /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; @@ -2033,7 +2033,7 @@ da2_render_text(da2_t *da2) } /* right half of DBCS */ else { - uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->scanline, da2); /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; @@ -2042,7 +2042,7 @@ da2_render_text(da2_t *da2) chr_wide = 0; } /* Line 28 (Underscore) Note: Draw this first to display blink + vertical + underline correctly. */ - if (da2->sc == da2->crtc[LC_UNDERLINE_LOCATION] && attr & 0x40 && !colormode) { /* Underscore only in monochrome mode */ + if (da2->scanline == da2->crtc[LC_UNDERLINE_LOCATION] && attr & 0x40 && !colormode) { /* Underscore only in monochrome mode */ for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[fg]]; /* under line (white) */ } @@ -2050,13 +2050,13 @@ da2_render_text(da2_t *da2) if (attr & 0x10) { p[0] = da2->pallook[da2->egapal[(colormode) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* vertical line (white) */ } - if (da2->sc == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) { /* HGrid */ + if (da2->scanline == 0 && attr & 0x20 && ~da2->attrc[LV_PAS_STATUS_CNTRL]) { /* HGrid */ for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[(colormode) ? IRGBtoBGRI(da2->attrc[LV_GRID_COLOR_0]) : 2]]; /* horizontal line (white) */ } /* Drawing text cursor */ - drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); - if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { + drawcursor = ((da2->memaddr == da2->cursoraddr) && da2->cursorvisible && da2->cursoron); + if (drawcursor && da2->scanline >= da2->crtc[LC_CURSOR_ROW_START] && da2->scanline <= da2->crtc[LC_CURSOR_ROW_END]) { int cursorwidth = (da2->crtc[LC_COMPATIBILITY] & 0x20 ? 26 : 13); int cursorcolor = (colormode) ? IRGBtoBGRI(da2->attrc[LV_CURSOR_COLOR]) : 2; /* Choose color 2 if mode 8 */ fg = (colormode) ? getPS55ForeColor(attr, da2) : ((attr & 0x08) ? 3 : 2); @@ -2071,10 +2071,10 @@ da2_render_text(da2_t *da2) else p[n] = (p[n] == da2->pallook[da2->egapal[bg]]) ? da2->pallook[da2->egapal[cursorcolor]] : p[n]; } - da2->ma += 2; + da2->memaddr += 2; p += 13; } - // da2->ma &= DA2_MASK_CRAM; + // da2->memaddr &= DA2_MASK_CRAM; // da2->writelines++; } } @@ -2096,12 +2096,12 @@ da2_render_textm3(da2_t *da2) int fg, bg; uint32_t chr_dbcs; int chr_wide = 0; - // da2_log("\nda2ma: %x, da2sc: %x\n", da2->ma, da2->sc); + // da2_log("\nda2ma: %x, da2sc: %x\n", da2->memaddr, da2->scanline); for (x = 0; x < da2->hdisp; x += 13) { - chr = da2_vram_r(DA2_VM03_BASECHR + da2->ma, da2); - attr = da2_vram_r(DA2_VM03_BASECHR + da2->ma + 1, da2); - extattr = da2_vram_r(DA2_VM03_BASEEXATTR + da2->ma + 1, da2); - // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (DA2_VM03_BASECHR + da2->ma << 1) & da2->vram_mask, chr, attr); + chr = da2_vram_r(DA2_VM03_BASECHR + da2->memaddr, da2); + attr = da2_vram_r(DA2_VM03_BASECHR + da2->memaddr + 1, da2); + extattr = da2_vram_r(DA2_VM03_BASEEXATTR + da2->memaddr + 1, da2); + // if(chr!=0x20) da2_log("addr: %x, chr: %x, attr: %x ", (DA2_VM03_BASECHR + da2->memaddr << 1) & da2->vram_mask, chr, attr); bg = attr >> 4; // if (da2->blink) bg &= ~0x8; // fg = (da2->blink || (!(attr & 0x80))) ? (attr & 0xf) : bg; @@ -2118,11 +2118,11 @@ da2_render_textm3(da2_t *da2) /* Stay drawing if the char code is DBCS and not at last column. */ if (chr_wide) { /* Get high DBCS code from the next video address */ - chr_dbcs = da2_vram_r(DA2_VM03_BASECHR + da2->ma + 2, da2); + chr_dbcs = da2_vram_r(DA2_VM03_BASECHR + da2->memaddr + 2, da2); chr_dbcs <<= 8; chr_dbcs |= chr; /* Get the font pattern */ - uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->scanline, da2); /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x80000000) ? fg : bg]]; @@ -2135,10 +2135,10 @@ da2_render_textm3(da2_t *da2) fontbase = DA2_GAIJIRAM_SBEX; else fontbase = DA2_GAIJIRAM_SBCS; - uint16_t font = da2->mmio.ram[fontbase+ chr * 0x40 + da2->sc * 2]; /* w13xh29 font */ + uint16_t font = da2->mmio.ram[fontbase+ chr * 0x40 + da2->scanline * 2]; /* w13xh29 font */ font <<= 8; - font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->sc * 2 + 1]; /* w13xh29 font */ - // if(chr!=0x20) da2_log("ma: %x, sc: %x, chr: %x, font: %x ", da2->ma, da2->sc, chr, font); + font |= da2->mmio.ram[fontbase + chr * 0x40 + da2->scanline * 2 + 1]; /* w13xh29 font */ + // if(chr!=0x20) da2_log("memaddr: %x, scanline: %x, chr: %x, font: %x ", da2->memaddr, da2->scanline, chr, font); for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; font <<= 1; @@ -2147,7 +2147,7 @@ da2_render_textm3(da2_t *da2) } /* right half of DBCS */ else { - uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->sc, da2); + uint32_t font = getfont_ps55dbcs(chr_dbcs, da2->scanline, da2); /* Draw 13 dots */ for (uint32_t n = 0; n < 13; n++) { p[n] = da2->pallook[da2->egapal[(font & 0x8000) ? fg : bg]]; @@ -2155,8 +2155,8 @@ da2_render_textm3(da2_t *da2) } chr_wide = 0; } - drawcursor = ((da2->ma == da2->ca) && da2->con && da2->cursoron); - if (drawcursor && da2->sc >= da2->crtc[LC_CURSOR_ROW_START] && da2->sc <= da2->crtc[LC_CURSOR_ROW_END]) { + drawcursor = ((da2->memaddr == da2->cursoraddr) && da2->cursorvisible && da2->cursoron); + if (drawcursor && da2->scanline >= da2->crtc[LC_CURSOR_ROW_START] && da2->scanline <= da2->crtc[LC_CURSOR_ROW_END]) { // int cursorwidth = (da2->crtc[0x1f] & 0x20 ? 26 : 13); // int cursorcolor = (colormode) ? IRGBtoBGRI(da2->attrc[0x1a]) : 2;/* Choose color 2 if mode 8 */ // fg = (colormode) ? getPS55ForeColor(attr, da2) : (attr & 0x08) ? 3 : 2; @@ -2168,10 +2168,10 @@ da2_render_textm3(da2_t *da2) for (uint32_t n = 0; n < 13; n++) p[n] = da2->pallook[da2->egapal[fg]]; } - da2->ma += 2; + da2->memaddr += 2; p += 13; } - // da2->ma &= DA2_MASK_CRAM; + // da2->memaddr &= DA2_MASK_CRAM; // da2->writelines++; } } @@ -2179,8 +2179,8 @@ da2_render_textm3(da2_t *da2) static void da2_render_color_4bpp(da2_t *da2) { - int changed_offset = da2->ma >> 9; - // da2_log("ma %x cf %x\n", da2->ma, changed_offset); + int changed_offset = da2->memaddr >> 9; + // da2_log("memaddr %x cf %x\n", da2->memaddr, changed_offset); da2->plane_mask &= 0x0f; /*safety */ if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) { @@ -2191,7 +2191,7 @@ da2_render_color_4bpp(da2_t *da2) if (da2->firstline_draw == 2000) da2->firstline_draw = da2->displine; da2->lastline_draw = da2->displine; - // da2_log("d %X\n", da2->ma); + // da2_log("d %X\n", da2->memaddr); for (x = 0; x <= da2->hdisp; x += 8) /* hdisp = 1024 */ { @@ -2199,9 +2199,9 @@ da2_render_color_4bpp(da2_t *da2) uint8_t dat; /* get 8 pixels from vram */ - da2->ma &= da2->vram_display_mask; - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&da2->vram[da2->ma << 3]); - da2->ma += 1; + da2->memaddr &= da2->vram_display_mask; + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&da2->vram[da2->memaddr << 3]); + da2->memaddr += 1; dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)); p[0] = da2->pallook[da2->egapal[dat & da2->plane_mask]]; @@ -2228,8 +2228,8 @@ da2_render_color_4bpp(da2_t *da2) static void da2_render_color_8bpp(da2_t *da2) { - int changed_offset = da2->ma >> 9; - // da2_log("ma %x cf %x\n", da2->ma, changed_offset); + int changed_offset = da2->memaddr >> 9; + // da2_log("memaddr %x cf %x\n", da2->memaddr, changed_offset); if (da2->changedvram[changed_offset] || da2->changedvram[changed_offset + 1] || da2->fullchange) { int x; @@ -2239,7 +2239,7 @@ da2_render_color_8bpp(da2_t *da2) if (da2->firstline_draw == 2000) da2->firstline_draw = da2->displine; da2->lastline_draw = da2->displine; - // da2_log("d %X\n", da2->ma); + // da2_log("d %X\n", da2->memaddr); for (x = 0; x <= da2->hdisp; x += 8) /* hdisp = 1024 */ { @@ -2247,10 +2247,10 @@ da2_render_color_8bpp(da2_t *da2) uint8_t dat; /* get 8 pixels from vram */ - da2->ma &= da2->vram_display_mask; - *(uint32_t *) (&edat[0]) = *(uint32_t *) (&da2->vram[da2->ma << 3]); - *(uint32_t *) (&edat[4]) = *(uint32_t *) (&da2->vram[(da2->ma << 3) + 4]); - da2->ma += 1; + da2->memaddr &= da2->vram_display_mask; + *(uint32_t *) (&edat[0]) = *(uint32_t *) (&da2->vram[da2->memaddr << 3]); + *(uint32_t *) (&edat[4]) = *(uint32_t *) (&da2->vram[(da2->memaddr << 3) + 4]); + da2->memaddr += 1; dat = ((edat[0] >> 7) & (1 << 0)) | ((edat[1] >> 6) & (1 << 1)) | ((edat[2] >> 5) & (1 << 2)) | ((edat[3] >> 4) & (1 << 3)) | ((edat[4] >> 3) & (1 << 4)) | ((edat[5] >> 2) & (1 << 5)) | ((edat[6] >> 1) & (1 << 6)) | ((edat[7] >> 0) & (1 << 7)); p[0] = da2->pallook[dat]; @@ -2343,9 +2343,9 @@ da2_recalctimings(da2_t *da2) if (da2->rowoffset == 0) da2->rowoffset = 64 * 2; /* To avoid causing a DBZ error */ if (da2->split == 0) /* To avoid a glitch in MODE 1 of OS/2 J1.3 DOSBox. */ - da2->ma_latch = 0; + da2->memaddr_latch = 0; else - da2->ma_latch = ((da2->crtc[LC_START_ADDRESS_HIGH] & 0x3ff) << 8) | da2->crtc[LC_START_ADDRESS_LOW]; + da2->memaddr_latch = ((da2->crtc[LC_START_ADDRESS_HIGH] & 0x3ff) << 8) | da2->crtc[LC_START_ADDRESS_LOW]; da2->ca_adj = 0; da2->rowcount = da2->crtc[LC_MAXIMUM_SCAN_LINE]; @@ -3022,7 +3022,7 @@ da2_poll(void *priv) if (da2->dispon) { da2->hdisp_on = 1; - da2->ma &= da2->vram_display_mask; + da2->memaddr &= da2->vram_display_mask; if (da2->firstline == 2000) { da2->firstline = da2->displine; video_wait_for_buffer(); @@ -3035,7 +3035,7 @@ da2_poll(void *priv) da2->lastline = da2->displine; } - // da2_log("%03i %06X %06X\n", da2->displine, da2->ma,da2->vram_display_mask); + // da2_log("%03i %06X %06X\n", da2->displine, da2->memaddr,da2->vram_display_mask); da2->displine++; if ((da2->cgastat & 8) && ((da2->displine & 0xf) == (da2->crtc[LC_VERTICAL_SYNC_END] & 0xf)) && da2->vslines) { // da2_log("Vsync off at line %i\n",displine); @@ -3045,9 +3045,9 @@ da2_poll(void *priv) if (da2->displine > 1200) da2->displine = 0; // da2_log("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], - // displine, vc, ma); + // displine, vc, memaddr); } else { - // da2_log("VC %i ma %05X\n", da2->vc, da2->ma); + // da2_log("VC %i memaddr %05X\n", da2->vc, da2->memaddr); timer_advance_u64(&da2->timer, da2->dispontime); if (da2->dispon) @@ -3055,20 +3055,20 @@ da2_poll(void *priv) da2->hdisp_on = 0; da2->linepos = 0; - if (da2->sc == (da2->crtc[LC_CURSOR_ROW_END] & 31)) - da2->con = 0; + if (da2->scanline == (da2->crtc[LC_CURSOR_ROW_END] & 31)) + da2->cursorvisible = 0; if (da2->dispon) { - if (da2->sc == da2->rowcount) { + if (da2->scanline == da2->rowcount) { da2->linecountff = 0; - da2->sc = 0; + da2->scanline = 0; - da2->maback += (da2->rowoffset << 1); /* color = 0x50(80), mono = 0x40(64) */ - da2->maback &= da2->vram_display_mask; - da2->ma = da2->maback; + da2->memaddr_backup += (da2->rowoffset << 1); /* color = 0x50(80), mono = 0x40(64) */ + da2->memaddr_backup &= da2->vram_display_mask; + da2->memaddr = da2->memaddr_backup; } else { - da2->sc++; - da2->sc &= 31; - da2->ma = da2->maback; + da2->scanline++; + da2->scanline &= 31; + da2->memaddr = da2->memaddr_backup; } } @@ -3076,9 +3076,9 @@ da2_poll(void *priv) da2->vc &= 2047; if (da2->vc == da2->split) { - // da2->ma = da2->maback = da2->hblank_sub; - da2->ma = da2->maback = 0; - da2->sc = 0; + // da2->memaddr = da2->memaddr_backup = da2->hblank_sub; + da2->memaddr = da2->memaddr_backup = 0; + da2->scanline = 0; // da2->displine = 0; } @@ -3128,24 +3128,24 @@ da2_poll(void *priv) changeframecount = 2; da2->vslines = 0; - da2->ma - = da2->maback = da2->ma_latch << 1; - da2->ca = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; - da2->ca <<= 1; + da2->memaddr + = da2->memaddr_backup = da2->memaddr_latch << 1; + da2->cursoraddr = ((da2->crtc[LC_CURSOR_LOC_HIGH] << 8) | da2->crtc[LC_CURSOR_LOC_LOWJ]) + da2->ca_adj; + da2->cursoraddr <<= 1; - // da2_log("Addr %08X vson %03X vsoff %01X\n",da2->ma,da2->vsyncstart,da2->crtc[0x11]&0xF); + // da2_log("Addr %08X vson %03X vsoff %01X\n",da2->memaddr,da2->vsyncstart,da2->crtc[0x11]&0xF); } if (da2->vc == da2->vtotal) { // da2_log("VC vtotal\n"); // printf("Frame over at line %i %i %i %i\n",displine,vc,da2_vsyncstart,da2_dispend); da2->vc = 0; - da2->sc = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; + da2->scanline = da2->crtc[LC_PRESET_ROW_SCANJ] & 0x1f; da2->dispon = 1; da2->displine = 0; da2->scrollcache = da2->attrc[LV_PANNING] & 7; } - if (da2->sc == (da2->crtc[LC_CURSOR_ROW_START] & 31)) - da2->con = 1; + if (da2->scanline == (da2->crtc[LC_CURSOR_ROW_START] & 31)) + da2->cursorvisible = 1; } } @@ -3231,7 +3231,7 @@ da2_reset(void *priv) da2->attrc[LV_CURSOR_COLOR] = 0x0f; /* cursor color */ da2->crtc[LC_HORIZONTAL_TOTAL] = 63; /* Horizontal Total */ da2->crtc[LC_VERTICAL_TOTALJ] = 255; /* Vertical Total (These two must be set before the timer starts.) */ - da2->ma_latch = 0; + da2->memaddr_latch = 0; da2->attrc[LV_CURSOR_CONTROL] = 0x13; /* cursor options */ da2->attr_palette_enable = 0; /* disable attribute generator */ @@ -3441,7 +3441,7 @@ static const device_config_t da2_configuration[] = { // clang-format off { .name = "charset", - .description = "Charset", + .description = "Character set", .type = CONFIG_SELECTION, .default_int = DA2_DCONFIG_CHARSET_JPAN, .selection = { diff --git a/src/video/vid_rtg310x.c b/src/video/vid_rtg310x.c index ae9475d96..813d30bf3 100644 --- a/src/video/vid_rtg310x.c +++ b/src/video/vid_rtg310x.c @@ -180,7 +180,7 @@ rtg_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -211,7 +211,7 @@ rtg_recalctimings(svga_t *svga) { const rtg_t *dev = (rtg_t *) svga->priv; - svga->ma_latch |= ((svga->crtc[0x19] & 0x10) << 16) | ((svga->crtc[0x19] & 0x40) << 17); + svga->memaddr_latch |= ((svga->crtc[0x19] & 0x10) << 16) | ((svga->crtc[0x19] & 0x40) << 17); svga->interlace = (svga->crtc[0x19] & 1); diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 99521f061..d0495dca0 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -3179,9 +3179,9 @@ s3_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); if ((((svga->crtc[0x67] & 0xc) != 0xc) && (s3->chip >= S3_TRIO64V)) || (s3->chip < S3_TRIO64V)) - svga->ma_latch |= (s3->ma_ext << 16); + svga->memaddr_latch |= (s3->ma_ext << 16); } else { svga->fullchange = svga->monitor->mon_changeframecount; svga_recalctimings(svga); @@ -3503,7 +3503,7 @@ s3_recalctimings(svga_t *svga) } svga->hdisp = svga->hdisp_old; - svga->ma_latch |= (s3->ma_ext << 16); + svga->memaddr_latch |= (s3->ma_ext << 16); svga->lowres = (!!(svga->attrregs[0x10] & 0x40) && !(svga->crtc[0x3a] & 0x10)); @@ -4379,7 +4379,7 @@ s3_trio64v_recalctimings(svga_t *svga) if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ { - svga->ma_latch |= (s3->ma_ext << 16); + svga->memaddr_latch |= (s3->ma_ext << 16); if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; else if (svga->crtc[0x43] & 0x04) @@ -4427,9 +4427,9 @@ s3_trio64v_recalctimings(svga_t *svga) } else /*Streams mode*/ { if (s3->streams.buffer_ctrl & 1) - svga->ma_latch = s3->streams.pri_fb1 >> 2; + svga->memaddr_latch = s3->streams.pri_fb1 >> 2; else - svga->ma_latch = s3->streams.pri_fb0 >> 2; + svga->memaddr_latch = s3->streams.pri_fb0 >> 2; svga->hdisp = s3->streams.pri_w + 1; if (s3->streams.pri_h < svga->dispend) diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 1b61c02d5..774b0d4b7 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -211,6 +211,7 @@ typedef struct virge_t { uint8_t pci_regs[256]; uint8_t pci_slot; + uint8_t type; int chip; int bilinear_enabled; @@ -688,10 +689,10 @@ s3_virge_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); if ((svga->crtc[0x67] & 0xc) != 0xc) - svga->ma_latch |= (virge->ma_ext << 16); + svga->memaddr_latch |= (virge->ma_ext << 16); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -890,7 +891,7 @@ s3_virge_recalctimings(svga_t *svga) } if ((svga->crtc[0x67] & 0xc) != 0xc) { /*VGA mode*/ - svga->ma_latch |= (virge->ma_ext << 16); + svga->memaddr_latch |= (virge->ma_ext << 16); if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; else if (svga->crtc[0x43] & 0x04) @@ -935,9 +936,9 @@ s3_virge_recalctimings(svga_t *svga) } else { /*Streams mode*/ if (virge->chip < S3_VIRGEGX2) { if (virge->streams.buffer_ctrl & 1) - svga->ma_latch = virge->streams.pri_fb1 >> 2; + svga->memaddr_latch = virge->streams.pri_fb1 >> 2; else - svga->ma_latch = virge->streams.pri_fb0 >> 2; + svga->memaddr_latch = virge->streams.pri_fb0 >> 2; svga->hdisp = virge->streams.pri_w + 1; if (virge->streams.pri_h < svga->dispend) @@ -946,7 +947,7 @@ s3_virge_recalctimings(svga_t *svga) svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; } else { - svga->ma_latch |= (virge->ma_ext << 16); + svga->memaddr_latch |= (virge->ma_ext << 16); if (svga->crtc[0x51] & 0x30) svga->rowoffset |= (svga->crtc[0x51] & 0x30) << 4; else if (svga->crtc[0x43] & 0x04) @@ -5140,9 +5141,11 @@ s3_virge_init(const device_t *info) virge_t *virge = (virge_t *) calloc(1, sizeof(virge_t)); reset_state = calloc(1, sizeof(virge_t)); + virge->type = (info->local & 0xff); + virge->bilinear_enabled = device_get_config_int("bilinear"); virge->dithering_enabled = device_get_config_int("dithering"); - if (info->local >= S3_VIRGE_GX2) + if (virge->type >= S3_VIRGE_GX2) virge->memory_size = 4; else virge->memory_size = device_get_config_int("memory"); @@ -5150,7 +5153,7 @@ s3_virge_init(const device_t *info) virge->onboard = !!(info->local & 0x100); if (!virge->onboard) - switch (info->local) { + switch (virge->type) { case S3_VIRGE_325: bios_fn = ROM_VIRGE_325; break; @@ -5197,7 +5200,7 @@ s3_virge_init(const device_t *info) virge->svga.hwcursor.cur_ysize = 64; if (bios_fn != NULL) { - if (info->local == S3_VIRGE_GX2) + if (virge->type == S3_VIRGE_GX2) rom_init(&virge->bios_rom, bios_fn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); else rom_init(&virge->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); @@ -5251,7 +5254,7 @@ s3_virge_init(const device_t *info) virge->virge_id = 0xe1; virge->is_agp = !!(info->flags & DEVICE_AGP); - switch (info->local) { + switch (virge->type) { case S3_VIRGE_325: case S3_DIAMOND_STEALTH3D_2000: case S3_MIROCRYSTAL_3D: @@ -5356,7 +5359,7 @@ s3_virge_init(const device_t *info) default: break; } - if (info->local == S3_VIRGE_GX) + if (virge->type == S3_VIRGE_GX) virge->svga.crtc[0x36] |= (1 << 2); } diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index c54af7119..6be21ce69 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -151,14 +151,14 @@ typedef struct sigma_t { uint8_t sigmamode; /* Mode control register [0x2D8] */ - uint16_t ma, maback; + uint16_t memaddr, memaddr_backup; int crtcreg; /* CRTC: Real selected register */ int linepos, displine; - int sc, vc; + int scanline, vc; int cgadispon; - int con, cursoron, cgablink; + int cursorvisible, cursoron, cgablink; int vsynctime, vadj; int oddeven; @@ -414,23 +414,23 @@ sigma_text80(sigma_t *sigma) { uint8_t chr; uint8_t attr; - uint16_t ca = (sigma->crtc[15] | (sigma->crtc[14] << 8)); - uint16_t ma = ((sigma->ma & 0x3FFF) << 1); + uint16_t cursoraddr = (sigma->crtc[15] | (sigma->crtc[14] << 8)); + uint16_t memaddr = ((sigma->memaddr & 0x3FFF) << 1); int drawcursor; uint32_t cols[4]; - const uint8_t *vram = sigma->vram + (ma << 1); + const uint8_t *vram = sigma->vram + (memaddr << 1); - ca = ca << 1; + cursoraddr = cursoraddr << 1; if (sigma->sigma_ctl & CTL_CURSOR) - ++ca; - ca &= 0x3fff; + ++cursoraddr; + cursoraddr &= 0x3fff; /* The Sigma 400 seems to use screen widths stated in words (40 for 80-column, 20 for 40-column) */ for (uint32_t x = 0; x < (sigma->crtc[1] << 1); x++) { chr = vram[x << 1]; attr = vram[(x << 1) + 1]; - drawcursor = ((ma == ca) && sigma->con && sigma->cursoron); + drawcursor = ((memaddr == cursoraddr) && sigma->cursorvisible && sigma->cursoron); if (!(sigma->sigmamode & MODE_NOBLINK)) { cols[1] = (attr & 15) | 16; @@ -445,22 +445,22 @@ sigma_text80(sigma_t *sigma) if (drawcursor) { for (uint8_t c = 0; c < 8; c++) { if (sigma->sigmamode & MODE_FONT16) - buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->scanline & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; else - buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; } } else { for (uint8_t c = 0; c < 8; c++) { if (sigma->sigmamode & MODE_FONT16) - buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->scanline & 15] & (1 << (c ^ 7))) ? 1 : 0]; else - buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[sigma->displine][(x << 3) + c + 8] = cols[(fontdat[chr][sigma->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; } } - ++ma; + ++memaddr; } - sigma->ma += sigma->crtc[1]; + sigma->memaddr += sigma->crtc[1]; } /* Render a line in 40-column text mode */ @@ -469,23 +469,23 @@ sigma_text40(sigma_t *sigma) { uint8_t chr; uint8_t attr; - uint16_t ca = (sigma->crtc[15] | (sigma->crtc[14] << 8)); - uint16_t ma = ((sigma->ma & 0x3FFF) << 1); + uint16_t cursoraddr = (sigma->crtc[15] | (sigma->crtc[14] << 8)); + uint16_t memaddr = ((sigma->memaddr & 0x3FFF) << 1); int drawcursor; uint32_t cols[4]; - const uint8_t *vram = sigma->vram + ((ma << 1) & 0x3FFF); + const uint8_t *vram = sigma->vram + ((memaddr << 1) & 0x3FFF); - ca = ca << 1; + cursoraddr = cursoraddr << 1; if (sigma->sigma_ctl & CTL_CURSOR) - ++ca; - ca &= 0x3fff; + ++cursoraddr; + cursoraddr &= 0x3fff; /* The Sigma 400 seems to use screen widths stated in words (40 for 80-column, 20 for 40-column) */ for (uint32_t x = 0; x < (sigma->crtc[1] << 1); x++) { chr = vram[x << 1]; attr = vram[(x << 1) + 1]; - drawcursor = ((ma == ca) && sigma->con && sigma->cursoron); + drawcursor = ((memaddr == cursoraddr) && sigma->cursorvisible && sigma->cursoron); if (!(sigma->sigmamode & MODE_NOBLINK)) { cols[1] = (attr & 15) | 16; @@ -499,24 +499,24 @@ sigma_text40(sigma_t *sigma) if (drawcursor) { for (uint8_t c = 0; c < 8; c++) { - buffer32->line[sigma->displine][(x << 4) + 2 * c + 8] = buffer32->line[sigma->displine][(x << 4) + 2 * c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; + buffer32->line[sigma->displine][(x << 4) + 2 * c + 8] = buffer32->line[sigma->displine][(x << 4) + 2 * c + 9] = cols[(fontdatm[chr][sigma->scanline & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xf; } } else { for (uint8_t c = 0; c < 8; c++) { - buffer32->line[sigma->displine][(x << 4) + 2 * c + 8] = buffer32->line[sigma->displine][(x << 4) + 2 * c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + buffer32->line[sigma->displine][(x << 4) + 2 * c + 8] = buffer32->line[sigma->displine][(x << 4) + 2 * c + 9] = cols[(fontdatm[chr][sigma->scanline & 15] & (1 << (c ^ 7))) ? 1 : 0]; } } - ma++; + memaddr++; } - sigma->ma += sigma->crtc[1]; + sigma->memaddr += sigma->crtc[1]; } /* Draw a line in the 640x400 graphics mode */ static void sigma_gfx400(sigma_t *sigma) { - const uint8_t *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + (sigma->sc & 3) * 0x2000]; + const uint8_t *vram = &sigma->vram[((sigma->memaddr << 1) & 0x1FFF) + (sigma->scanline & 3) * 0x2000]; uint8_t plane[4]; uint8_t col; @@ -532,7 +532,7 @@ sigma_gfx400(sigma_t *sigma) buffer32->line[sigma->displine][(x << 3) + c + 8] = col; } if (x & 1) - ++sigma->ma; + ++sigma->memaddr; } } @@ -544,7 +544,7 @@ sigma_gfx400(sigma_t *sigma) static void sigma_gfx200(sigma_t *sigma) { - const uint8_t *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + (sigma->sc & 2) * 0x1000]; + const uint8_t *vram = &sigma->vram[((sigma->memaddr << 1) & 0x1FFF) + (sigma->scanline & 2) * 0x1000]; uint8_t plane[4]; uint8_t col; @@ -561,7 +561,7 @@ sigma_gfx200(sigma_t *sigma) } if (x & 1) - ++sigma->ma; + ++sigma->memaddr; } } @@ -569,7 +569,7 @@ sigma_gfx200(sigma_t *sigma) static void sigma_gfx4col(sigma_t *sigma) { - const uint8_t *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + (sigma->sc & 2) * 0x1000]; + const uint8_t *vram = &sigma->vram[((sigma->memaddr << 1) & 0x1FFF) + (sigma->scanline & 2) * 0x1000]; uint8_t plane[4]; uint8_t mask; uint8_t col; @@ -592,7 +592,7 @@ sigma_gfx4col(sigma_t *sigma) } if (x & 1) - ++sigma->ma; + ++sigma->memaddr; } } @@ -604,15 +604,15 @@ sigma_poll(void *priv) int c; int oldvc; uint32_t cols[4]; - int oldsc; + int scanline_old; if (!sigma->linepos) { timer_advance_u64(&sigma->timer, sigma->dispofftime); sigma->sigmastat |= STATUS_RETR_H; sigma->linepos = 1; - oldsc = sigma->sc; + scanline_old = sigma->scanline; if ((sigma->crtc[8] & 3) == 3) - sigma->sc = ((sigma->sc << 1) + sigma->oddeven) & 7; + sigma->scanline = ((sigma->scanline << 1) + sigma->oddeven) & 7; if (sigma->cgadispon) { if (sigma->displine < sigma->firstline) { sigma->firstline = sigma->displine; @@ -660,8 +660,8 @@ sigma_poll(void *priv) video_process_8(x, sigma->displine); - sigma->sc = oldsc; - if (sigma->vc == sigma->crtc[7] && !sigma->sc) + sigma->scanline = scanline_old; + if (sigma->vc == sigma->crtc[7] && !sigma->scanline) sigma->sigmastat |= STATUS_RETR_V; sigma->displine++; if (sigma->displine >= 560) @@ -674,24 +674,24 @@ sigma_poll(void *priv) if (!sigma->vsynctime) sigma->sigmastat &= ~STATUS_RETR_V; } - if (sigma->sc == (sigma->crtc[11] & 31) || ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[11] & 31) >> 1))) { - sigma->con = 0; + if (sigma->scanline == (sigma->crtc[11] & 31) || ((sigma->crtc[8] & 3) == 3 && sigma->scanline == ((sigma->crtc[11] & 31) >> 1))) { + sigma->cursorvisible = 0; } - if ((sigma->crtc[8] & 3) == 3 && sigma->sc == (sigma->crtc[9] >> 1)) - sigma->maback = sigma->ma; + if ((sigma->crtc[8] & 3) == 3 && sigma->scanline == (sigma->crtc[9] >> 1)) + sigma->memaddr_backup = sigma->memaddr; if (sigma->vadj) { - sigma->sc++; - sigma->sc &= 31; - sigma->ma = sigma->maback; + sigma->scanline++; + sigma->scanline &= 31; + sigma->memaddr = sigma->memaddr_backup; sigma->vadj--; if (!sigma->vadj) { sigma->cgadispon = 1; - sigma->ma = sigma->maback = (sigma->crtc[13] | (sigma->crtc[12] << 8)) & 0x3fff; - sigma->sc = 0; + sigma->memaddr = sigma->memaddr_backup = (sigma->crtc[13] | (sigma->crtc[12] << 8)) & 0x3fff; + sigma->scanline = 0; } - } else if (sigma->sc == sigma->crtc[9]) { - sigma->maback = sigma->ma; - sigma->sc = 0; + } else if (sigma->scanline == sigma->crtc[9]) { + sigma->memaddr_backup = sigma->memaddr; + sigma->scanline = 0; oldvc = sigma->vc; sigma->vc++; sigma->vc &= 127; @@ -705,7 +705,7 @@ sigma_poll(void *priv) if (!sigma->vadj) sigma->cgadispon = 1; if (!sigma->vadj) - sigma->ma = sigma->maback = (sigma->crtc[13] | (sigma->crtc[12] << 8)) & 0x3fff; + sigma->memaddr = sigma->memaddr_backup = (sigma->crtc[13] | (sigma->crtc[12] << 8)) & 0x3fff; if ((sigma->crtc[10] & 0x60) == 0x20) sigma->cursoron = 0; else @@ -768,14 +768,14 @@ sigma_poll(void *priv) sigma->oddeven ^= 1; } } else { - sigma->sc++; - sigma->sc &= 31; - sigma->ma = sigma->maback; + sigma->scanline++; + sigma->scanline &= 31; + sigma->memaddr = sigma->memaddr_backup; } if (sigma->cgadispon) sigma->sigmastat &= ~STATUS_RETR_H; - if (sigma->sc == (sigma->crtc[10] & 31) || ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[10] & 31) >> 1))) - sigma->con = 1; + if (sigma->scanline == (sigma->crtc[10] & 31) || ((sigma->crtc[8] & 3) == 3 && sigma->scanline == ((sigma->crtc[10] & 31) >> 1))) + sigma->cursorvisible = 1; } } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 0c9c24241..2899f3bf7 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -280,9 +280,11 @@ svga_out(uint16_t addr, uint8_t val, void *priv) case 0x3c2: svga->miscout = val; svga->vidclock = val & 4; - io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->priv); - if (!(val & 1)) - io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->priv); + if (svga->priv_parent == NULL) { + io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->priv); + if (!(val & 1)) + io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->priv); + } svga_recalctimings(svga); break; case 0x3c3: @@ -754,7 +756,7 @@ svga_recalctimings(svga_t *svga) svga->interlace = 0; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); svga->ca_adj = 0; svga->rowcount = svga->crtc[9] & 0x1f; @@ -915,7 +917,7 @@ svga_recalctimings(svga_t *svga) if (vblankend <= svga->vblankstart) vblankend += 0x00000080; - if (svga->hoverride) { + if (svga->hoverride || svga->override) { if (svga->hdisp >= 2048) svga->monitor->mon_overscan_x = 0; @@ -956,14 +958,18 @@ svga_recalctimings(svga_t *svga) svga->hdisp -= (svga->hblank_sub * svga->dots_per_clock); svga->left_overscan = svga->x_add = (svga->htotal - adj_dot - 1) * svga->dots_per_clock; - svga->monitor->mon_overscan_x = svga->x_add + (svga->hblankstart * svga->dots_per_clock) - hd; + svga->monitor->mon_overscan_x = svga->x_add + (svga->hblankstart * svga->dots_per_clock) - hd + svga->dots_per_clock; + /* Compensate for the HDISP code above. */ + if (svga->crtc[1] & 1) + svga->monitor->mon_overscan_x++; if ((svga->hdisp >= 2048) || (svga->left_overscan < 0)) { svga->left_overscan = svga->x_add = 0; svga->monitor->mon_overscan_x = 0; } - svga->y_add = svga->vtotal - vblankend + 1; + /* - 1 because + 1 but also - 2 to compensate for the + 2 added to vtotal above. */ + svga->y_add = svga->vtotal - vblankend - 1; svga->monitor->mon_overscan_y = svga->y_add + abs(svga->vblankstart - svga->dispend); if ((svga->dispend >= 2048) || (svga->y_add < 0)) { @@ -1283,17 +1289,17 @@ svga_poll(void *priv) if (svga->dispon) { svga->hdisp_on = 1; - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; if (svga->firstline == 2000) { svga->firstline = svga->displine; video_wait_for_buffer_monitor(svga->monitor_index); } if (svga->hwcursor_on || svga->dac_hwcursor_on || svga->overlay_on) - svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = svga->interlace ? 3 : 2; + svga->changedvram[svga->memaddr >> 12] = svga->changedvram[(svga->memaddr >> 12) + 1] = svga->interlace ? 3 : 2; if (svga->vertical_linedbl) { - old_ma = svga->ma; + old_ma = svga->memaddr; svga->displine <<= 1; svga->y_add <<= 1; @@ -1302,7 +1308,7 @@ svga_poll(void *priv) svga->displine++; - svga->ma = old_ma; + svga->memaddr = old_ma; svga_do_render(svga); @@ -1331,29 +1337,29 @@ svga_poll(void *priv) svga->hdisp_on = 0; svga->linepos = 0; - if ((svga->sc == (svga->crtc[11] & 31)) || (svga->sc == svga->rowcount)) - svga->con = 0; + if ((svga->scanline == (svga->crtc[11] & 31)) || (svga->scanline == svga->rowcount)) + svga->cursorvisible = 0; if (svga->dispon) { /* TODO: Verify real hardware behaviour for out-of-range fine vertical scroll - - S3 Trio64V2/DX: sc == rowcount, wrapping 5-bit counter. */ + - S3 Trio64V2/DX: scanline == rowcount, wrapping 5-bit counter. */ if (svga->linedbl && !svga->linecountff) { svga->linecountff = 1; - svga->ma = svga->maback; - } else if (svga->sc == svga->rowcount) { + svga->memaddr = svga->memaddr_backup; + } else if (svga->scanline == svga->rowcount) { svga->linecountff = 0; - svga->sc = 0; + svga->scanline = 0; - svga->maback += (svga->adv_flags & FLAG_NO_SHIFT3) ? svga->rowoffset : (svga->rowoffset << 3); + svga->memaddr_backup += (svga->adv_flags & FLAG_NO_SHIFT3) ? svga->rowoffset : (svga->rowoffset << 3); if (svga->interlace) - svga->maback += (svga->adv_flags & FLAG_NO_SHIFT3) ? svga->rowoffset : (svga->rowoffset << 3); + svga->memaddr_backup += (svga->adv_flags & FLAG_NO_SHIFT3) ? svga->rowoffset : (svga->rowoffset << 3); - svga->maback &= svga->vram_display_mask; - svga->ma = svga->maback; + svga->memaddr_backup &= svga->vram_display_mask; + svga->memaddr = svga->memaddr_backup; } else { svga->linecountff = 0; - svga->sc++; - svga->sc &= 0x1f; - svga->ma = svga->maback; + svga->scanline++; + svga->scanline &= 0x1f; + svga->memaddr = svga->memaddr_backup; } } @@ -1373,14 +1379,14 @@ svga_poll(void *priv) if (ret) { if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = (svga->rowoffset << 1) + svga->hblank_sub; + svga->memaddr = svga->memaddr_backup = (svga->rowoffset << 1) + svga->hblank_sub; else - svga->ma = svga->maback = svga->hblank_sub; + svga->memaddr = svga->memaddr_backup = svga->hblank_sub; - svga->ma = (svga->ma << 2); - svga->maback = (svga->maback << 2); + svga->memaddr = (svga->memaddr << 2); + svga->memaddr_backup = (svga->memaddr_backup << 2); - svga->sc = 0; + svga->scanline = 0; if (svga->attrregs[0x10] & 0x20) { svga->scrollcache = 0; svga->x_add = svga->left_overscan; @@ -1449,16 +1455,16 @@ svga_poll(void *priv) svga->vslines = 0; if (svga->interlace && svga->oddeven) - svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1) + svga->hblank_sub; + svga->memaddr = svga->memaddr_backup = svga->memaddr_latch + (svga->rowoffset << 1) + svga->hblank_sub; else - svga->ma = svga->maback = svga->ma_latch + svga->hblank_sub; + svga->memaddr = svga->memaddr_backup = svga->memaddr_latch + svga->hblank_sub; - svga->ca = ((svga->crtc[0xe] << 8) | svga->crtc[0xf]) + ((svga->crtc[0xb] & 0x60) >> 5) + svga->ca_adj; + svga->cursoraddr = ((svga->crtc[0xe] << 8) | svga->crtc[0xf]) + ((svga->crtc[0xb] & 0x60) >> 5) + svga->ca_adj; if (!(svga->adv_flags & FLAG_NO_SHIFT3)) { - svga->ma = (svga->ma << 2); - svga->maback = (svga->maback << 2); + svga->memaddr = (svga->memaddr << 2); + svga->memaddr_backup = (svga->memaddr_backup << 2); } - svga->ca = (svga->ca << 2); + svga->cursoraddr = (svga->cursoraddr << 2); if (svga->vsync_callback) svga->vsync_callback(svga); @@ -1468,7 +1474,7 @@ svga_poll(void *priv) #endif if (svga->vc == svga->vtotal) { svga->vc = 0; - svga->sc = (svga->crtc[0x8] & 0x1f); + svga->scanline = (svga->crtc[0x8] & 0x1f); svga->dispon = 1; svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; @@ -1502,8 +1508,8 @@ svga_poll(void *priv) svga->overlay_on = 0; svga->overlay_latch = svga->overlay; } - if (svga->sc == (svga->crtc[10] & 31)) - svga->con = 1; + if (svga->scanline == (svga->crtc[10] & 31)) + svga->cursorvisible = 1; } } diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index d47697a7e..bdb496686 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -156,13 +156,13 @@ svga_render_text_40(svga_t *svga) for (int x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { if (!svga->force_old_addr) - addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; + addr = svga->remap_func(svga, svga->memaddr) & svga->vram_display_mask; - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + drawcursor = ((svga->memaddr == svga->cursoraddr) && svga->cursorvisible && svga->cursoron); if (svga->force_old_addr) { - chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + chr = svga->vram[(svga->memaddr << 1) & svga->vram_display_mask]; + attr = svga->vram[((svga->memaddr << 1) + 1) & svga->vram_display_mask]; } else { chr = svga->vram[addr]; attr = svga->vram[addr + 1]; @@ -187,7 +187,7 @@ svga_render_text_40(svga_t *svga) } } - dat = svga->vram[charaddr + (svga->sc << 2)]; + dat = svga->vram[charaddr + (svga->scanline << 2)]; if (svga->seqregs[1] & 1) { for (xx = 0; xx < 16; xx += 2) p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; @@ -199,10 +199,10 @@ svga_render_text_40(svga_t *svga) else p[16] = p[17] = (dat & 1) ? fg : bg; } - svga->ma += 4; + svga->memaddr += 4; p += xinc; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } @@ -239,13 +239,13 @@ svga_render_text_80(svga_t *svga) for (int x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { if (!svga->force_old_addr) - addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; + addr = svga->remap_func(svga, svga->memaddr) & svga->vram_display_mask; - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + drawcursor = ((svga->memaddr == svga->cursoraddr) && svga->cursorvisible && svga->cursoron); if (svga->force_old_addr) { - chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + chr = svga->vram[(svga->memaddr << 1) & svga->vram_display_mask]; + attr = svga->vram[((svga->memaddr << 1) + 1) & svga->vram_display_mask]; } else { chr = svga->vram[addr]; attr = svga->vram[addr + 1]; @@ -269,7 +269,7 @@ svga_render_text_80(svga_t *svga) } } - dat = svga->vram[charaddr + (svga->sc << 2)]; + dat = svga->vram[charaddr + (svga->scanline << 2)]; if (svga->seqregs[1] & 1) { for (xx = 0; xx < 8; xx++) p[xx] = (dat & (0x80 >> xx)) ? fg : bg; @@ -281,10 +281,10 @@ svga_render_text_80(svga_t *svga) else p[8] = (dat & 1) ? fg : bg; } - svga->ma += 4; + svga->memaddr += 4; p += xinc; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } @@ -317,8 +317,8 @@ svga_render_text_80_ksc5601(svga_t *svga) xinc = (svga->seqregs[1] & 1) ? 8 : 9; for (int x = 0; x < (svga->hdisp + svga->scrollcache); x += xinc) { - uint32_t addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; - drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + uint32_t addr = svga->remap_func(svga, svga->memaddr) & svga->vram_display_mask; + drawcursor = ((svga->memaddr == svga->cursoraddr) && svga->cursorvisible && svga->cursoron); chr = svga->vram[addr]; nextchr = svga->vram[addr + 8]; attr = svga->vram[addr + 1]; @@ -338,7 +338,7 @@ svga_render_text_80_ksc5601(svga_t *svga) if ((x + xinc) < svga->hdisp && (chr & (nextchr | svga->ksc5601_sbyte_mask) & 0x80)) { if ((chr == svga->ksc5601_udc_area_msb[0] || chr == svga->ksc5601_udc_area_msb[1]) && (nextchr > 0xa0 && nextchr < 0xff)) - dat = fontdatksc5601_user[(chr == svga->ksc5601_udc_area_msb[1] ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc]; + dat = fontdatksc5601_user[(chr == svga->ksc5601_udc_area_msb[1] ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->scanline]; else if (nextchr & 0x80) { if (svga->ksc5601_swap_mode == 1 && (nextchr > 0xa0 && nextchr < 0xff)) { if (chr >= 0x80 && chr < 0x99) @@ -346,7 +346,7 @@ svga_render_text_80_ksc5601(svga_t *svga) else if (chr >= 0xB0 && chr < 0xC9) chr -= 0x30; } - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc]; + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->scanline]; } else dat = 0xff; } else { @@ -356,9 +356,9 @@ svga_render_text_80_ksc5601(svga_t *svga) charaddr = svga->charseta + (chr * 128); if ((svga->ksc5601_english_font_type >> 8) == 1) - dat = fontdatksc5601[((svga->ksc5601_english_font_type & 0x7F) << 7) | (chr >> 1)].chr[((chr & 1) << 4) | svga->sc]; + dat = fontdatksc5601[((svga->ksc5601_english_font_type & 0x7F) << 7) | (chr >> 1)].chr[((chr & 1) << 4) | svga->scanline]; else - dat = svga->vram[charaddr + (svga->sc << 2)]; + dat = svga->vram[charaddr + (svga->scanline << 2)]; } if (svga->seqregs[1] & 1) { @@ -372,11 +372,11 @@ svga_render_text_80_ksc5601(svga_t *svga) else p[8] = (dat & 1) ? fg : bg; } - svga->ma += 4; + svga->memaddr += 4; p += xinc; if ((x + xinc) < svga->hdisp && (chr & (nextchr | svga->ksc5601_sbyte_mask) & 0x80)) { - attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + attr = svga->vram[((svga->memaddr << 1) + 1) & svga->vram_display_mask]; if (drawcursor) { bg = svga->pallook[svga->egapal[attr & 15] & svga->dac_mask]; @@ -392,9 +392,9 @@ svga_render_text_80_ksc5601(svga_t *svga) } if ((chr == svga->ksc5601_udc_area_msb[0] || chr == svga->ksc5601_udc_area_msb[1]) && (nextchr > 0xa0 && nextchr < 0xff)) - dat = fontdatksc5601_user[(chr == svga->ksc5601_udc_area_msb[1] ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc + 16]; + dat = fontdatksc5601_user[(chr == svga->ksc5601_udc_area_msb[1] ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->scanline + 16]; else if (nextchr & 0x80) - dat = fontdatksc5601[((chr & 0x7f) << 7) | (nextchr & 0x7F)].chr[svga->sc + 16]; + dat = fontdatksc5601[((chr & 0x7f) << 7) | (nextchr & 0x7F)].chr[svga->scanline + 16]; else dat = 0xff; @@ -410,12 +410,12 @@ svga_render_text_80_ksc5601(svga_t *svga) p[8] = (dat & 1) ? fg : bg; } - svga->ma += 4; + svga->memaddr += 4; p += xinc; x += xinc; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } @@ -433,7 +433,7 @@ svga_render_2bpp_s3_lowres(svga_t *svga) return; if (svga->force_old_addr) { - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + changed_offset = ((svga->memaddr << 1) + (svga->scanline & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -443,32 +443,32 @@ svga_render_2bpp_s3_lowres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->ma; + addr = svga->memaddr; if (!(svga->crtc[0x17] & 0x40)) { addr = (addr << 1) & svga->vram_mask; addr &= ~7; - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + if ((svga->crtc[0x17] & 0x20) && (svga->memaddr & 0x20000)) addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + if (!(svga->crtc[0x17] & 0x20) && (svga->memaddr & 0x8000)) addr |= 4; } if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + addr = (addr & ~0x8000) | ((svga->scanline & 1) ? 0x8000 : 0); if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + addr = (addr & ~0x10000) | ((svga->scanline & 2) ? 0x10000 : 0); dat[0] = svga->vram[addr]; dat[1] = svga->vram[addr | 0x1]; if (svga->seqregs[1] & 4) - svga->ma += 2; + svga->memaddr += 2; else - svga->ma += 4; - svga->ma &= svga->vram_mask; + svga->memaddr += 4; + svga->memaddr &= svga->vram_mask; p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3] & svga->dac_mask]; p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3] & svga->dac_mask]; p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3] & svga->dac_mask]; @@ -481,7 +481,7 @@ svga_render_2bpp_s3_lowres(svga_t *svga) } } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -491,16 +491,16 @@ svga_render_2bpp_s3_lowres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 16) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat[0] = svga->vram[addr]; dat[1] = svga->vram[addr | 0x1]; if (svga->seqregs[1] & 4) - svga->ma += 2; + svga->memaddr += 2; else - svga->ma += 4; + svga->memaddr += 4; - svga->ma &= svga->vram_mask; + svga->memaddr &= svga->vram_mask; p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3] & svga->dac_mask]; p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3] & svga->dac_mask]; @@ -531,7 +531,7 @@ svga_render_2bpp_s3_highres(svga_t *svga) return; if (svga->force_old_addr) { - changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + changed_offset = ((svga->memaddr << 1) + (svga->scanline & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -541,32 +541,32 @@ svga_render_2bpp_s3_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->ma; + addr = svga->memaddr; if (!(svga->crtc[0x17] & 0x40)) { addr = (addr << 1) & svga->vram_mask; addr &= ~7; - if ((svga->crtc[0x17] & 0x20) && (svga->ma & 0x20000)) + if ((svga->crtc[0x17] & 0x20) && (svga->memaddr & 0x20000)) addr |= 4; - if (!(svga->crtc[0x17] & 0x20) && (svga->ma & 0x8000)) + if (!(svga->crtc[0x17] & 0x20) && (svga->memaddr & 0x8000)) addr |= 4; } if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + addr = (addr & ~0x8000) | ((svga->scanline & 1) ? 0x8000 : 0); if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + addr = (addr & ~0x10000) | ((svga->scanline & 2) ? 0x10000 : 0); dat[0] = svga->vram[addr]; dat[1] = svga->vram[addr | 0x1]; if (svga->seqregs[1] & 4) - svga->ma += 2; + svga->memaddr += 2; else - svga->ma += 4; - svga->ma &= svga->vram_mask; + svga->memaddr += 4; + svga->memaddr &= svga->vram_mask; p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3] & svga->dac_mask]; p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3] & svga->dac_mask]; p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3] & svga->dac_mask]; @@ -579,7 +579,7 @@ svga_render_2bpp_s3_highres(svga_t *svga) } } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -589,16 +589,16 @@ svga_render_2bpp_s3_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat[0] = svga->vram[addr]; dat[1] = svga->vram[addr | 0x1]; if (svga->seqregs[1] & 4) - svga->ma += 2; + svga->memaddr += 2; else - svga->ma += 4; + svga->memaddr += 4; - svga->ma &= svga->vram_mask; + svga->memaddr &= svga->vram_mask; p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3] & svga->dac_mask]; p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3] & svga->dac_mask]; @@ -628,7 +628,7 @@ svga_render_2bpp_headland_highres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -638,7 +638,7 @@ svga_render_2bpp_headland_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); oddeven = 0; if (svga->seqregs[1] & 4) { @@ -649,8 +649,8 @@ svga_render_2bpp_headland_highres(svga_t *svga) } else { *(uint32_t *) (&edat[0]) = *(uint32_t *) (&svga->vram[addr]); } - svga->ma += 4; - svga->ma &= svga->vram_mask; + svga->memaddr += 4; + svga->memaddr &= svga->vram_mask; dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask] & svga->dac_mask]; @@ -736,9 +736,9 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) return; if (svga->force_old_addr) - changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + changed_offset = (svga->memaddr + (svga->scanline & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; else - changed_offset = svga->remap_func(svga, svga->ma) >> 12; + changed_offset = svga->remap_func(svga, svga->memaddr) >> 12; if (!(svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange)) return; @@ -755,19 +755,19 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) if (load_counter == 0) { /* Find our address */ if (svga->force_old_addr) { - addr = ((svga->ma & ~0x3) << incbypow2); + addr = ((svga->memaddr & ~0x3) << incbypow2); if (incbypow2 == 2) { - if (svga->ma & (4 << 15)) + if (svga->memaddr & (4 << 15)) addr |= 0x8; - if (svga->ma & (4 << 14)) + if (svga->memaddr & (4 << 14)) addr |= 0x4; } else if (incbypow2 == 1) { if ((svga->crtc[0x17] & 0x20)) { - if (svga->ma & (4 << 15)) + if (svga->memaddr & (4 << 15)) addr |= 0x4; } else { - if (svga->ma & (4 << 13)) + if (svga->memaddr & (4 << 13)) addr |= 0x4; } } else { @@ -775,13 +775,13 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) } if (!(svga->crtc[0x17] & 0x01)) - addr = (addr & ~0x8000) | ((svga->sc & 1) ? 0x8000 : 0); + addr = (addr & ~0x8000) | ((svga->scanline & 1) ? 0x8000 : 0); if (!(svga->crtc[0x17] & 0x02)) - addr = (addr & ~0x10000) | ((svga->sc & 2) ? 0x10000 : 0); + addr = (addr & ~0x10000) | ((svga->scanline & 2) ? 0x10000 : 0); } else if (svga->remap_required) - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); else - addr = svga->ma; + addr = svga->memaddr; addr &= svga->vram_display_mask; @@ -819,9 +819,9 @@ svga_render_indexed_gfx(svga_t *svga, bool highres, bool combine8bits) incr_counter += 1; if (incr_counter >= incevery) { incr_counter = 0; - svga->ma += 4; + svga->memaddr += 4; /* DISCREPANCY TODO FIXME 2/4bpp used vram_mask, 8bpp used vram_display_mask --GM */ - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } uint32_t current_shift = shift_values; @@ -926,7 +926,7 @@ svga_render_8bpp_clone_highres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -934,25 +934,25 @@ svga_render_8bpp_clone_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp /* + svga->scrollcache*/); x += 8) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); p[0] = svga->map8[dat & svga->dac_mask & 0xff]; p[1] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[2] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[3] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - dat = *(uint32_t *) (&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + 4) & svga->vram_display_mask]); p[4] = svga->map8[dat & svga->dac_mask & 0xff]; p[5] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[6] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[7] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - svga->ma += 8; + svga->memaddr += 8; p += 8; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -963,35 +963,35 @@ svga_render_8bpp_clone_highres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp /* + svga->scrollcache*/); x += 8) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); p[0] = svga->map8[dat & svga->dac_mask & 0xff]; p[1] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[2] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[3] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - dat = *(uint32_t *) (&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + 4) & svga->vram_display_mask]); p[4] = svga->map8[dat & svga->dac_mask & 0xff]; p[5] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[6] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[7] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - svga->ma += 8; + svga->memaddr += 8; p += 8; } } else { for (x = 0; x <= (svga->hdisp /* + svga->scrollcache*/); x += 4) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); p[0] = svga->map8[dat & svga->dac_mask & 0xff]; p[1] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[2] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[3] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - svga->ma += 4; + svga->memaddr += 4; p += 4; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1011,7 +1011,7 @@ svga_render_8bpp_lowres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1019,20 +1019,20 @@ svga_render_8bpp_lowres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); p[0] = p[1] = svga->map8[dat & 0xff]; p[2] = p[3] = svga->map8[(dat >> 8) & 0xff]; p[4] = p[5] = svga->map8[(dat >> 16) & 0xff]; p[6] = p[7] = svga->map8[(dat >> 24) & 0xff]; - svga->ma += 4; + svga->memaddr += 4; p += 8; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1043,29 +1043,29 @@ svga_render_8bpp_lowres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); p[0] = p[1] = svga->map8[dat & svga->dac_mask & 0xff]; p[2] = p[3] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[4] = p[5] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[6] = p[7] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - svga->ma += 4; + svga->memaddr += 4; p += 8; } } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); p[0] = p[1] = svga->map8[dat & svga->dac_mask & 0xff]; p[2] = p[3] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[4] = p[5] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[6] = p[7] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - svga->ma += 4; + svga->memaddr += 4; p += 8; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1083,7 +1083,7 @@ svga_render_8bpp_highres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1091,25 +1091,25 @@ svga_render_8bpp_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp /* + svga->scrollcache*/); x += 8) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); p[0] = svga->map8[dat & svga->dac_mask & 0xff]; p[1] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[2] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[3] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - dat = *(uint32_t *) (&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + 4) & svga->vram_display_mask]); p[4] = svga->map8[dat & svga->dac_mask & 0xff]; p[5] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[6] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[7] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - svga->ma += 8; + svga->memaddr += 8; p += 8; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1120,35 +1120,35 @@ svga_render_8bpp_highres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp /* + svga->scrollcache*/); x += 8) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); p[0] = svga->map8[dat & svga->dac_mask & 0xff]; p[1] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[2] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[3] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - dat = *(uint32_t *) (&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + 4) & svga->vram_display_mask]); p[4] = svga->map8[dat & svga->dac_mask & 0xff]; p[5] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[6] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[7] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - svga->ma += 8; + svga->memaddr += 8; p += 8; } } else { for (x = 0; x <= (svga->hdisp /* + svga->scrollcache*/); x += 4) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); p[0] = svga->map8[dat & svga->dac_mask & 0xff]; p[1] = svga->map8[(dat >> 8) & svga->dac_mask & 0xff]; p[2] = svga->map8[(dat >> 16) & svga->dac_mask & 0xff]; p[3] = svga->map8[(dat >> 24) & svga->dac_mask & 0xff]; - svga->ma += 4; + svga->memaddr += 4; p += 4; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1163,7 +1163,7 @@ svga_render_8bpp_tseng_lowres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1171,7 +1171,7 @@ svga_render_8bpp_tseng_lowres(svga_t *svga) svga->lastline_draw = svga->displine; for (int x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); if (svga->attrregs[0x10] & 0x80) dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[0] = p[1] = svga->map8[dat & svga->dac_mask & 0xff]; @@ -1188,10 +1188,10 @@ svga_render_8bpp_tseng_lowres(svga_t *svga) dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[6] = p[7] = svga->map8[dat & svga->dac_mask & 0xff]; - svga->ma += 4; + svga->memaddr += 4; p += 8; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } @@ -1204,7 +1204,7 @@ svga_render_8bpp_tseng_highres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1212,7 +1212,7 @@ svga_render_8bpp_tseng_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (int x = 0; x <= (svga->hdisp /* + svga->scrollcache*/); x += 8) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); if (svga->attrregs[0x10] & 0x80) dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[0] = svga->map8[dat & svga->dac_mask & 0xff]; @@ -1229,7 +1229,7 @@ svga_render_8bpp_tseng_highres(svga_t *svga) dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[3] = svga->map8[dat & svga->dac_mask & 0xff]; - dat = *(uint32_t *) (&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + 4) & svga->vram_display_mask]); if (svga->attrregs[0x10] & 0x80) dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[4] = svga->map8[dat & svga->dac_mask & 0xff]; @@ -1246,10 +1246,10 @@ svga_render_8bpp_tseng_highres(svga_t *svga) dat = (dat & ~0xf0) | ((svga->attrregs[0x14] & 0x0f) << 4); p[7] = svga->map8[dat & svga->dac_mask & 0xff]; - svga->ma += 8; + svga->memaddr += 8; p += 8; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } @@ -1266,7 +1266,7 @@ svga_render_15bpp_lowres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1274,21 +1274,21 @@ svga_render_15bpp_lowres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); p[x << 1] = p[(x << 1) + 1] = svga->conv_16to32(svga, dat & 0xffff, 15); p[(x << 1) + 2] = p[(x << 1) + 3] = svga->conv_16to32(svga, dat >> 16, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); p[(x << 1) + 4] = p[(x << 1) + 5] = svga->conv_16to32(svga, dat & 0xffff, 15); p[(x << 1) + 6] = p[(x << 1) + 7] = svga->conv_16to32(svga, dat >> 16, 15); } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; + svga->memaddr += x << 1; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1299,28 +1299,28 @@ svga_render_15bpp_lowres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); *p++ = svga->conv_16to32(svga, dat >> 16, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); *p++ = svga->conv_16to32(svga, dat >> 16, 15); } - svga->ma += x << 1; + svga->memaddr += x << 1; } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); *p++ = svga->conv_16to32(svga, dat >> 16, 15); - svga->ma += 4; + svga->memaddr += 4; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1338,7 +1338,7 @@ svga_render_15bpp_highres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1346,27 +1346,27 @@ svga_render_15bpp_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); p[x] = svga->conv_16to32(svga, dat & 0xffff, 15); p[x + 1] = svga->conv_16to32(svga, dat >> 16, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); p[x + 2] = svga->conv_16to32(svga, dat & 0xffff, 15); p[x + 3] = svga->conv_16to32(svga, dat >> 16, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 8) & svga->vram_display_mask]); p[x + 4] = svga->conv_16to32(svga, dat & 0xffff, 15); p[x + 5] = svga->conv_16to32(svga, dat >> 16, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 12) & svga->vram_display_mask]); p[x + 6] = svga->conv_16to32(svga, dat & 0xffff, 15); p[x + 7] = svga->conv_16to32(svga, dat >> 16, 15); } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; + svga->memaddr += x << 1; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1377,34 +1377,34 @@ svga_render_15bpp_highres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); *p++ = svga->conv_16to32(svga, dat >> 16, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); *p++ = svga->conv_16to32(svga, dat >> 16, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 8) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); *p++ = svga->conv_16to32(svga, dat >> 16, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 12) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); *p++ = svga->conv_16to32(svga, dat >> 16, 15); } - svga->ma += x << 1; + svga->memaddr += x << 1; } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 15); *p++ = svga->conv_16to32(svga, dat >> 16, 15); - svga->ma += 4; + svga->memaddr += 4; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1419,7 +1419,7 @@ svga_render_15bpp_mix_lowres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1427,20 +1427,20 @@ svga_render_15bpp_mix_lowres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); p[x << 1] = p[(x << 1) + 1] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); dat >>= 16; p[(x << 1) + 2] = p[(x << 1) + 3] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); p[(x << 1) + 4] = p[(x << 1) + 5] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); dat >>= 16; p[(x << 1) + 6] = p[(x << 1) + 7] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; + svga->memaddr += x << 1; + svga->memaddr &= svga->vram_display_mask; } } @@ -1454,7 +1454,7 @@ svga_render_15bpp_mix_highres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1462,28 +1462,28 @@ svga_render_15bpp_mix_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); p[x] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); dat >>= 16; p[x + 1] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); p[x + 2] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); dat >>= 16; p[x + 3] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 8) & svga->vram_display_mask]); p[x + 4] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); dat >>= 16; p[x + 5] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 12) & svga->vram_display_mask]); p[x + 6] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); dat >>= 16; p[x + 7] = (dat & 0x00008000) ? svga->pallook[dat & 0xff] : svga->conv_16to32(svga, dat & 0xffff, 15); } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; + svga->memaddr += x << 1; + svga->memaddr &= svga->vram_display_mask; } } @@ -1500,7 +1500,7 @@ svga_render_16bpp_lowres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1508,19 +1508,19 @@ svga_render_16bpp_lowres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); p[x << 1] = p[(x << 1) + 1] = svga->conv_16to32(svga, dat & 0xffff, 16); p[(x << 1) + 2] = p[(x << 1) + 3] = svga->conv_16to32(svga, dat >> 16, 16); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); p[(x << 1) + 4] = p[(x << 1) + 5] = svga->conv_16to32(svga, dat & 0xffff, 16); p[(x << 1) + 6] = p[(x << 1) + 7] = svga->conv_16to32(svga, dat >> 16, 16); } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; + svga->memaddr += x << 1; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1531,28 +1531,28 @@ svga_render_16bpp_lowres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); *p++ = svga->conv_16to32(svga, dat >> 16, 16); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); *p++ = svga->conv_16to32(svga, dat >> 16, 16); } - svga->ma += x << 1; + svga->memaddr += x << 1; } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); *p++ = svga->conv_16to32(svga, dat >> 16, 16); } - svga->ma += 4; + svga->memaddr += 4; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1570,7 +1570,7 @@ svga_render_16bpp_highres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1578,27 +1578,27 @@ svga_render_16bpp_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - uint32_t dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + uint32_t dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); p[x] = svga->conv_16to32(svga, dat & 0xffff, 16); p[x + 1] = svga->conv_16to32(svga, dat >> 16, 16); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); p[x + 2] = svga->conv_16to32(svga, dat & 0xffff, 16); p[x + 3] = svga->conv_16to32(svga, dat >> 16, 16); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 8) & svga->vram_display_mask]); p[x + 4] = svga->conv_16to32(svga, dat & 0xffff, 16); p[x + 5] = svga->conv_16to32(svga, dat >> 16, 16); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 12) & svga->vram_display_mask]); p[x + 6] = svga->conv_16to32(svga, dat & 0xffff, 16); p[x + 7] = svga->conv_16to32(svga, dat >> 16, 16); } - svga->ma += x << 1; - svga->ma &= svga->vram_display_mask; + svga->memaddr += x << 1; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1609,35 +1609,35 @@ svga_render_16bpp_highres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 8) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1)) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); *p++ = svga->conv_16to32(svga, dat >> 16, 16); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 4) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); *p++ = svga->conv_16to32(svga, dat >> 16, 16); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 8) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); *p++ = svga->conv_16to32(svga, dat >> 16, 16); - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 1) + 12) & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); *p++ = svga->conv_16to32(svga, dat >> 16, 16); } - svga->ma += x << 1; + svga->memaddr += x << 1; } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 2) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = svga->conv_16to32(svga, dat & 0xffff, 16); *p++ = svga->conv_16to32(svga, dat >> 16, 16); - svga->ma += 4; + svga->memaddr += 4; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1661,20 +1661,20 @@ svga_render_24bpp_lowres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); - svga->ma += 3; - svga->ma &= svga->vram_display_mask; + fg = svga->vram[svga->memaddr] | (svga->vram[svga->memaddr + 1] << 8) | (svga->vram[svga->memaddr + 2] << 16); + svga->memaddr += 3; + svga->memaddr &= svga->vram_display_mask; svga->monitor->target_buffer->line[svga->displine + svga->y_add][(x << 1) + svga->x_add] = svga->monitor->target_buffer->line[svga->displine + svga->y_add][(x << 1) + 1 + svga->x_add] = lookup_lut(fg); } } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1685,24 +1685,24 @@ svga_render_24bpp_lowres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat0 = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); - dat1 = *(uint32_t *) (&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); - dat2 = *(uint32_t *) (&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + dat0 = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); + dat1 = *(uint32_t *) (&svga->vram[(svga->memaddr + 4) & svga->vram_display_mask]); + dat2 = *(uint32_t *) (&svga->vram[(svga->memaddr + 8) & svga->vram_display_mask]); p[0] = p[1] = lookup_lut(dat0 & 0xffffff); p[2] = p[3] = lookup_lut((dat0 >> 24) | ((dat1 & 0xffff) << 8)); p[4] = p[5] = lookup_lut((dat1 >> 16) | ((dat2 & 0xff) << 16)); p[6] = p[7] = lookup_lut(dat2 >> 8); - svga->ma += 12; + svga->memaddr += 12; } } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat0 = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); - addr = svga->remap_func(svga, svga->ma + 4); + addr = svga->remap_func(svga, svga->memaddr + 4); dat1 = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); - addr = svga->remap_func(svga, svga->ma + 8); + addr = svga->remap_func(svga, svga->memaddr + 8); dat2 = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); p[0] = p[1] = lookup_lut(dat0 & 0xffffff); @@ -1710,10 +1710,10 @@ svga_render_24bpp_lowres(svga_t *svga) p[4] = p[5] = lookup_lut((dat1 >> 16) | ((dat2 & 0xff) << 16)); p[6] = p[7] = lookup_lut(dat2 >> 8); - svga->ma += 12; + svga->memaddr += 12; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1734,7 +1734,7 @@ svga_render_24bpp_highres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1742,24 +1742,24 @@ svga_render_24bpp_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); p[x] = lookup_lut(dat & 0xffffff); - dat = *(uint32_t *) (&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + 3) & svga->vram_display_mask]); p[x + 1] = lookup_lut(dat & 0xffffff); - dat = *(uint32_t *) (&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + 6) & svga->vram_display_mask]); p[x + 2] = lookup_lut(dat & 0xffffff); - dat = *(uint32_t *) (&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + 9) & svga->vram_display_mask]); p[x + 3] = lookup_lut(dat & 0xffffff); - svga->ma += 12; + svga->memaddr += 12; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1770,24 +1770,24 @@ svga_render_24bpp_highres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - dat0 = *(uint32_t *) (&svga->vram[svga->ma & svga->vram_display_mask]); - dat1 = *(uint32_t *) (&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); - dat2 = *(uint32_t *) (&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + dat0 = *(uint32_t *) (&svga->vram[svga->memaddr & svga->vram_display_mask]); + dat1 = *(uint32_t *) (&svga->vram[(svga->memaddr + 4) & svga->vram_display_mask]); + dat2 = *(uint32_t *) (&svga->vram[(svga->memaddr + 8) & svga->vram_display_mask]); *p++ = lookup_lut(dat0 & 0xffffff); *p++ = lookup_lut((dat0 >> 24) | ((dat1 & 0xffff) << 8)); *p++ = lookup_lut((dat1 >> 16) | ((dat2 & 0xff) << 16)); *p++ = lookup_lut(dat2 >> 8); - svga->ma += 12; + svga->memaddr += 12; } } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x += 4) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat0 = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); - addr = svga->remap_func(svga, svga->ma + 4); + addr = svga->remap_func(svga, svga->memaddr + 4); dat1 = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); - addr = svga->remap_func(svga, svga->ma + 8); + addr = svga->remap_func(svga, svga->memaddr + 8); dat2 = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = lookup_lut(dat0 & 0xffffff); @@ -1795,10 +1795,10 @@ svga_render_24bpp_highres(svga_t *svga) *p++ = lookup_lut((dat1 >> 16) | ((dat2 & 0xff) << 16)); *p++ = lookup_lut(dat2 >> 8); - svga->ma += 12; + svga->memaddr += 12; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1816,20 +1816,20 @@ svga_render_32bpp_lowres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->fullchange) { if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); - svga->ma += 4; - svga->ma &= svga->vram_display_mask; + dat = svga->vram[svga->memaddr] | (svga->vram[svga->memaddr + 1] << 8) | (svga->vram[svga->memaddr + 2] << 16); + svga->memaddr += 4; + svga->memaddr &= svga->vram_display_mask; svga->monitor->target_buffer->line[svga->displine + svga->y_add][(x << 1) + svga->x_add] = svga->monitor->target_buffer->line[svga->displine + svga->y_add][(x << 1) + 1 + svga->x_add] = lookup_lut(dat); } } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1840,20 +1840,20 @@ svga_render_32bpp_lowres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 2)) & svga->vram_display_mask]); *p++ = lookup_lut(dat & 0xffffff); *p++ = lookup_lut(dat & 0xffffff); } - svga->ma += (x * 4); + svga->memaddr += (x * 4); } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = lookup_lut(dat & 0xffffff); *p++ = lookup_lut(dat & 0xffffff); - svga->ma += 4; + svga->memaddr += 4; } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1872,7 +1872,7 @@ svga_render_32bpp_highres(svga_t *svga) return; if (svga->force_old_addr) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) { + if (svga->changedvram[svga->memaddr >> 12] || svga->changedvram[(svga->memaddr >> 12) + 1] || svga->changedvram[(svga->memaddr >> 12) + 2] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; if (svga->firstline_draw == 2000) @@ -1880,14 +1880,14 @@ svga_render_32bpp_highres(svga_t *svga) svga->lastline_draw = svga->displine; for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 2)) & svga->vram_display_mask]); p[x] = lookup_lut(dat & 0xffffff); } - svga->ma += 4; - svga->ma &= svga->vram_display_mask; + svga->memaddr += 4; + svga->memaddr &= svga->vram_display_mask; } } else { - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1898,20 +1898,20 @@ svga_render_32bpp_highres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 2)) & svga->vram_display_mask]); *p++ = lookup_lut(dat & 0xffffff); } - svga->ma += (x * 4); + svga->memaddr += (x * 4); } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = lookup_lut(dat & 0xffffff); - svga->ma += 4; + svga->memaddr += 4; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } } @@ -1928,7 +1928,7 @@ svga_render_ABGR8888_highres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1939,20 +1939,20 @@ svga_render_ABGR8888_highres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 2)) & svga->vram_display_mask]); *p++ = lookup_lut(((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16)); } - svga->ma += x * 4; + svga->memaddr += x * 4; } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = lookup_lut(((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16)); - svga->ma += 4; + svga->memaddr += 4; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } @@ -1968,7 +1968,7 @@ svga_render_RGBA8888_highres(svga_t *svga) if ((svga->displine + svga->y_add) < 0) return; - changed_addr = svga->remap_func(svga, svga->ma); + changed_addr = svga->remap_func(svga, svga->memaddr); if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { p = &svga->monitor->target_buffer->line[svga->displine + svga->y_add][svga->x_add]; @@ -1979,19 +1979,19 @@ svga_render_RGBA8888_highres(svga_t *svga) if (!svga->remap_required) { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - dat = *(uint32_t *) (&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + dat = *(uint32_t *) (&svga->vram[(svga->memaddr + (x << 2)) & svga->vram_display_mask]); *p++ = lookup_lut(dat >> 8); } - svga->ma += (x * 4); + svga->memaddr += (x * 4); } else { for (x = 0; x <= (svga->hdisp + svga->scrollcache); x++) { - addr = svga->remap_func(svga, svga->ma); + addr = svga->remap_func(svga, svga->memaddr); dat = *(uint32_t *) (&svga->vram[addr & svga->vram_display_mask]); *p++ = lookup_lut(dat >> 8); - svga->ma += 4; + svga->memaddr += 4; } } - svga->ma &= svga->vram_display_mask; + svga->memaddr &= svga->vram_display_mask; } } diff --git a/src/video/vid_tandy.c b/src/video/vid_tandy.c new file mode 100644 index 000000000..0609ca378 --- /dev/null +++ b/src/video/vid_tandy.c @@ -0,0 +1,827 @@ +/* + * 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. + * + * Tandy 1000 video emulation + * + * + * + * Authors: Sarah Walker, + * Miran Grca, + * Connor Hyde / starfrost, + * + * Copyright 2008-2019 Sarah Walker. + * Copyright 2016-2019 Miran Grca. + * Copyright 2025 starfrost + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/timer.h> +#include <86box/io.h> +#include <86box/pic.h> +#include <86box/pit.h> +#include <86box/nmi.h> +#include <86box/mem.h> +#include <86box/rom.h> +#include <86box/device.h> +#include <86box/nvr.h> +#include <86box/fdd.h> +#include <86box/fdc.h> +#include <86box/fdc_ext.h> +#include <86box/gameport.h> +#include <86box/keyboard.h> +#include <86box/sound.h> +#include <86box/snd_sn76489.h> +#include <86box/video.h> +#include <86box/vid_cga_comp.h> +#include <86box/m_tandy.h> +#include <86box/machine.h> +#include <86box/plat_unused.h> + +static uint8_t crtcmask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static uint8_t crtcmask_sl[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +enum { + TANDY_RGB = 0, + TANDY_COMPOSITE +}; + +static video_timings_t timing_dram = { VIDEO_BUS, 0, 0, 0, 0, 0, 0 }; /*No additional waitstates*/ + +static void +recalc_mapping(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + mem_mapping_disable(&vid->mapping); + io_removehandler(0x03d0, 16, + tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); + + if (vid->planar_ctrl & 4) { + mem_mapping_enable(&vid->mapping); + if (vid->array[5] & 1) + mem_mapping_set_addr(&vid->mapping, 0xa0000, 0x10000); + else + mem_mapping_set_addr(&vid->mapping, 0xb8000, 0x8000); + io_sethandler(0x03d0, 16, tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); + } +} + +static void +recalc_timings(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + double _dispontime; + double _dispofftime; + double disptime; + + if (vid->mode & 1) { + disptime = vid->crtc[0] + 1; + _dispontime = vid->crtc[1]; + } else { + disptime = (vid->crtc[0] + 1) << 1; + _dispontime = vid->crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + vid->dispontime = (uint64_t) (_dispontime); + vid->dispofftime = (uint64_t) (_dispofftime); +} + +static void +recalc_address(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + if ((vid->memctrl & 0xc0) == 0xc0) { + vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; + vid->b8000_mask = 0x7fff; + } else { + vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; + vid->b8000_mask = 0x3fff; + } +} + +void +tandy_recalc_address_sl(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + vid->b8000_limit = 0x8000; + + if (vid->array[5] & 1) { + vid->vram = &ram[((vid->memctrl & 0x04) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x20) << 11) + dev->base]; + } else if ((vid->memctrl & 0xc0) == 0xc0) { + vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; + } else { + vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; + if ((vid->memctrl & 0x38) == 0x38) + vid->b8000_limit = 0x4000; + } +} + +static void +vid_update_latch(t1kvid_t *vid) +{ + uint32_t lp_latch = vid->displine * vid->crtc[1]; + + vid->crtc[0x10] = (lp_latch >> 8) & 0x3f; + vid->crtc[0x11] = lp_latch & 0xff; +} + +void +tandy_vid_out(uint16_t addr, uint8_t val, void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + uint8_t old; + + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + + switch (addr) { + case 0x03d4: + vid->crtcreg = val & 0x1f; + break; + + case 0x03d5: + old = vid->crtc[vid->crtcreg]; + if (dev->is_sl2) + vid->crtc[vid->crtcreg] = val & crtcmask_sl[vid->crtcreg]; + else + vid->crtc[vid->crtcreg] = val & crtcmask[vid->crtcreg]; + if (old != val) { + if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { + vid->fullchange = changeframecount; + recalc_timings(dev); + } + } + break; + + case 0x03d8: + old = vid->mode; + vid->mode = val; + if ((old ^ val) & 0x01) + recalc_timings(dev); + if (!dev->is_sl2) + update_cga16_color(vid->mode); + break; + + case 0x03d9: + vid->col = val; + break; + + case 0x03da: + vid->array_index = val & 0x1f; + break; + + case 0x3db: + if (!dev->is_sl2 && (vid->lp_strobe == 1)) + vid->lp_strobe = 0; + break; + + case 0x3dc: + if (!dev->is_sl2 && (vid->lp_strobe == 0)) { + vid->lp_strobe = 1; + vid_update_latch(vid); + } + break; + + case 0x03de: + if (vid->array_index & 16) + val &= 0xf; + vid->array[vid->array_index & 0x1f] = val; + if (dev->is_sl2) { + if ((vid->array_index & 0x1f) == 5) { + recalc_mapping(dev); + tandy_recalc_address_sl(dev); + } + } + break; + + case 0x03df: + vid->memctrl = val; + if (dev->is_sl2) + tandy_recalc_address_sl(dev); + else + recalc_address(dev); + break; + + case 0x0065: + if (val == 8) + return; /*Hack*/ + vid->planar_ctrl = val; + recalc_mapping(dev); + break; + + default: + break; + } +} + +uint8_t +tandy_vid_in(uint16_t addr, void *priv) +{ + const tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + uint8_t ret = 0xff; + + if ((addr >= 0x3d0) && (addr <= 0x3d7)) + addr = (addr & 0xff9) | 0x004; + + switch (addr) { + case 0x03d4: + ret = vid->crtcreg; + break; + + case 0x03d5: + ret = vid->crtc[vid->crtcreg]; + break; + + case 0x03da: + ret = vid->status; + break; + + case 0x3db: + if (!dev->is_sl2 && (vid->lp_strobe == 1)) + vid->lp_strobe = 0; + break; + + case 0x3dc: + if (!dev->is_sl2 && (vid->lp_strobe == 0)) { + vid->lp_strobe = 1; + vid_update_latch(vid); + } + break; + + default: + break; + } + + return ret; +} + +static void +vid_write(uint32_t addr, uint8_t val, void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + + if (vid->memctrl == -1) + return; + + if (dev->is_sl2) { + if (vid->array[5] & 1) + vid->b8000[addr & 0xffff] = val; + else { + if ((addr & 0x7fff) < vid->b8000_limit) + vid->b8000[addr & 0x7fff] = val; + } + } else { + vid->b8000[addr & vid->b8000_mask] = val; + } +} + +static uint8_t +vid_read(uint32_t addr, void *priv) +{ + const tandy_t *dev = (tandy_t *) priv; + const t1kvid_t *vid = dev->vid; + + if (vid->memctrl == -1) + return 0xff; + + if (dev->is_sl2) { + if (vid->array[5] & 1) + return (vid->b8000[addr & 0xffff]); + if ((addr & 0x7fff) < vid->b8000_limit) + return (vid->b8000[addr & 0x7fff]); + else + return 0xff; + } else { + return (vid->b8000[addr & vid->b8000_mask]); + } +} + +static void +vid_poll(void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + t1kvid_t *vid = dev->vid; + uint16_t cursoraddr = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x; + int c; + int xs_temp; + int ys_temp; + int oldvc; + uint8_t chr; + uint8_t attr; + uint16_t dat; + int cols[4]; + int col; + int scanline_old; + + if (!vid->linepos) { + timer_advance_u64(&vid->timer, vid->dispofftime); + vid->status |= 1; + vid->linepos = 1; + scanline_old = vid->scanline; + if ((vid->crtc[8] & 3) == 3) + vid->scanline = (vid->scanline << 1) & 7; + if (vid->dispon) { + if (vid->displine < vid->firstline) { + vid->firstline = vid->displine; + video_wait_for_buffer(); + } + vid->lastline = vid->displine; + cols[0] = (vid->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) { + if (vid->array[3] & 4) { + buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = cols[0]; + if (vid->mode & 1) { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = cols[0]; + } else { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = cols[0]; + } + } else if ((vid->mode & 0x12) == 0x12) { + buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = 0; + if (vid->mode & 1) { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = 0; + } else { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = 0; + } + } else { + buffer32->line[vid->displine << 1][c] = buffer32->line[(vid->displine << 1) + 1][c] = (vid->col & 15) + 16; + if (vid->mode & 1) { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; + } else { + buffer32->line[vid->displine << 1][c + (vid->crtc[1] << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + } + } + } + if (dev->is_sl2 && (vid->array[5] & 1)) { /*640x200x16*/ + for (x = 0; x < vid->crtc[1] * 2; x++) { + dat = (vid->vram[(vid->memaddr << 1) & 0xffff] << 8) | vid->vram[((vid->memaddr << 1) + 1) & 0xffff]; + vid->memaddr++; + buffer32->line[vid->displine << 1][(x << 2) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 8] = vid->array[((dat >> 12) & 0xf) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 2) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 9] = vid->array[((dat >> 8) & 0xf) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 2) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 10] = vid->array[((dat >> 4) & 0xf) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 2) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 2) + 11] = vid->array[(dat & 0xf) + 16] + 16; + } + } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000) + 1]; + vid->memaddr++; + buffer32->line[vid->displine << 1][(x << 3) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8] = buffer32->line[vid->displine << 1][(x << 3) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 3) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 10] = buffer32->line[vid->displine << 1][(x << 3) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 3) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 12] = buffer32->line[vid->displine << 1][(x << 3) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 3) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 14] = buffer32->line[vid->displine << 1][(x << 3) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 15] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + } + } else if (vid->array[3] & 0x10) { /*160x200x16*/ + for (x = 0; x < vid->crtc[1]; x++) { + if (dev->is_sl2) { + dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000) + 1]; + } else { + dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000) + 1]; + } + vid->memaddr++; + buffer32->line[vid->displine << 1][(x << 4) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 8] = buffer32->line[vid->displine << 1][(x << 4) + 9] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 9] = buffer32->line[vid->displine << 1][(x << 4) + 10] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 10] = buffer32->line[vid->displine << 1][(x << 4) + 11] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 4) + 12] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 12] = buffer32->line[vid->displine << 1][(x << 4) + 13] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 13] = buffer32->line[vid->displine << 1][(x << 4) + 14] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 14] = buffer32->line[vid->displine << 1][(x << 4) + 15] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 4) + 16] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 16] = buffer32->line[vid->displine << 1][(x << 4) + 17] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 17] = buffer32->line[vid->displine << 1][(x << 4) + 18] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 18] = buffer32->line[vid->displine << 1][(x << 4) + 19] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1] & 0x0f) + 16] + 16; + buffer32->line[vid->displine << 1][(x << 4) + 20] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 20] = buffer32->line[vid->displine << 1][(x << 4) + 21] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 21] = buffer32->line[vid->displine << 1][(x << 4) + 22] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 22] = buffer32->line[vid->displine << 1][(x << 4) + 23] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + 23] = vid->array[(dat & vid->array[1] & 0x0f) + 16] + 16; + } + } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 3) * 0x2000) + 1]; + vid->memaddr++; + for (c = 0; c < 8; c++) { + chr = (dat >> 6) & 2; + chr |= ((dat >> 15) & 1); + buffer32->line[vid->displine << 1][(x << 3) + 8 + c] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; + dat <<= 1; + } + } + } else if (vid->mode & 1) { + for (x = 0; x < vid->crtc[1]; x++) { + chr = vid->vram[(vid->memaddr << 1) & 0x3fff]; + attr = vid->vram[((vid->memaddr << 1) + 1) & 0x3fff]; + drawcursor = ((vid->memaddr == cursoraddr) && vid->cursorvisible && vid->cursoron); + if (vid->mode & 0x20) { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; + } + if (vid->scanline & 8) { + for (c = 0; c < 8; c++) { + buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[0]; + } + } else { + for (c = 0; c < 8; c++) { + if (vid->scanline == 8) { + buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + } else { + buffer32->line[vid->displine << 1][(x << 3) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + if (drawcursor) { + for (c = 0; c < 8; c++) { + buffer32->line[vid->displine << 1][(x << 3) + c + 8] ^= 15; + buffer32->line[(vid->displine << 1) + 1][(x << 3) + c + 8] ^= 15; + } + } + vid->memaddr++; + } + } else if (!(vid->mode & 2)) { + for (x = 0; x < vid->crtc[1]; x++) { + chr = vid->vram[(vid->memaddr << 1) & 0x3fff]; + attr = vid->vram[((vid->memaddr << 1) + 1) & 0x3fff]; + drawcursor = ((vid->memaddr == cursoraddr) && vid->cursorvisible && vid->cursoron); + if (vid->mode & 0x20) { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; + } + vid->memaddr++; + if (vid->scanline & 8) { + for (c = 0; c < 8; c++) + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } else { + for (c = 0; c < 8; c++) { + if (vid->scanline == 8) { + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][7] & (1 << (c ^ 7))) ? 1 : 0]; + } else { + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->scanline & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + if (drawcursor) { + for (c = 0; c < 16; c++) { + buffer32->line[vid->displine << 1][(x << 4) + c + 8] ^= 15; + buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] ^= 15; + } + } + } + } else if (!(vid->mode & 16)) { + cols[0] = (vid->col & 15); + col = (vid->col & 16) ? 8 : 0; + if (vid->mode & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else if (vid->col & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + cols[0] = vid->array[(cols[0] & vid->array[1]) + 16] + 16; + cols[1] = vid->array[(cols[1] & vid->array[1]) + 16] + 16; + cols[2] = vid->array[(cols[2] & vid->array[1]) + 16] + 16; + cols[3] = vid->array[(cols[3] & vid->array[1]) + 16] + 16; + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000) + 1]; + vid->memaddr++; + for (c = 0; c < 8; c++) { + buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 8] = buffer32->line[vid->displine << 1][(x << 4) + (c << 1) + 1 + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } else { + cols[0] = 0; + cols[1] = vid->array[(vid->col & vid->array[1]) + 16] + 16; + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000)] << 8) | vid->vram[((vid->memaddr << 1) & 0x1fff) + ((vid->scanline & 1) * 0x2000) + 1]; + vid->memaddr++; + for (c = 0; c < 16; c++) { + buffer32->line[vid->displine << 1][(x << 4) + c + 8] = buffer32->line[(vid->displine << 1) + 1][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } else { + if (vid->array[3] & 4) { + if (vid->mode & 1) { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + } else { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + } + } else { + cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; + if (vid->mode & 1) { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 3) + 16, cols[0]); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 3) + 16, cols[0]); + } else { + hline(buffer32, 0, (vid->displine << 1), (vid->crtc[1] << 4) + 16, cols[0]); + hline(buffer32, 0, (vid->displine << 1) + 1, (vid->crtc[1] << 4) + 16, cols[0]); + } + } + } + + if (vid->mode & 1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + if (!dev->is_sl2 && vid->composite) { + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[vid->displine << 1]); + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[(vid->displine << 1) + 1]); + } else { + video_process_8(x, vid->displine << 1); + video_process_8(x, (vid->displine << 1) + 1); + } + vid->scanline = scanline_old; + if (vid->vc == vid->crtc[7] && !vid->scanline) + vid->status |= 8; + vid->displine++; + if (vid->displine >= 360) + vid->displine = 0; + } else { + timer_advance_u64(&vid->timer, vid->dispontime); + if (vid->dispon) + vid->status &= ~1; + vid->linepos = 0; + if (vid->vsynctime) { + vid->vsynctime--; + if (!vid->vsynctime) + vid->status &= ~8; + } + if (vid->scanline == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->scanline == ((vid->crtc[11] & 31) >> 1))) { + vid->cursorvisible = 0; + } + if (vid->vadj) { + vid->scanline++; + vid->scanline &= 31; + vid->memaddr = vid->memaddr_backup; + vid->vadj--; + if (!vid->vadj) { + vid->dispon = 1; + if (dev->is_sl2 && (vid->array[5] & 1)) + vid->memaddr = vid->memaddr_backup = vid->crtc[13] | (vid->crtc[12] << 8); + else + vid->memaddr = vid->memaddr_backup = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + vid->scanline = 0; + } + } else if (vid->scanline == vid->crtc[9] || ((vid->crtc[8] & 3) == 3 && vid->scanline == (vid->crtc[9] >> 1))) { + vid->memaddr_backup = vid->memaddr; + vid->scanline = 0; + oldvc = vid->vc; + vid->vc++; + if (dev->is_sl2) + vid->vc &= 255; + else + vid->vc &= 127; + if (vid->vc == vid->crtc[6]) + vid->dispon = 0; + if (oldvc == vid->crtc[4]) { + vid->vc = 0; + vid->vadj = vid->crtc[5]; + if (!vid->vadj) + vid->dispon = 1; + if (!vid->vadj) { + if (dev->is_sl2 && (vid->array[5] & 1)) + vid->memaddr = vid->memaddr_backup = vid->crtc[13] | (vid->crtc[12] << 8); + else + vid->memaddr = vid->memaddr_backup = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + } + if ((vid->crtc[10] & 0x60) == 0x20) + vid->cursoron = 0; + else + vid->cursoron = vid->blink & 16; + } + if (vid->vc == vid->crtc[7]) { + vid->dispon = 0; + vid->displine = 0; + vid->vsynctime = 16; + picint(1 << 5); + if (vid->crtc[7]) { + if (vid->mode & 1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + vid->lastline++; + + xs_temp = x; + ys_temp = (vid->lastline - vid->firstline) << 1; + + if ((xs_temp > 0) && (ys_temp > 0)) { + if (xs_temp < 64) + xs_temp = 656; + if (ys_temp < 32) + ys_temp = 400; + if (!enable_overscan) + xs_temp -= 16; + + if ((xs_temp != xsize) || (ys_temp != ysize) || video_force_resize_get()) { + xsize = xs_temp; + ysize = ys_temp; + set_screen_size(xsize, ysize + (enable_overscan ? 16 : 0)); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) { + video_blit_memtoscreen(0, (vid->firstline - 4) << 1, + xsize, ((vid->lastline - vid->firstline) + 8) << 1); + } else { + video_blit_memtoscreen(8, vid->firstline << 1, + xsize, (vid->lastline - vid->firstline) << 1); + } + } + + frames++; + + video_res_x = xsize; + video_res_y = ysize; + if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ + video_res_x /= 2; + video_bpp = 4; + } else if (vid->array[3] & 0x10) { /*160x200x16*/ + video_res_x /= 4; + video_bpp = 4; + } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + } else if (vid->mode & 1) { + video_res_x /= 8; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (!(vid->mode & 2)) { + video_res_x /= 16; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (!(vid->mode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else { + video_bpp = 1; + } + } + vid->firstline = 1000; + vid->lastline = 0; + vid->blink++; + } + } else { + vid->scanline++; + vid->scanline &= 31; + vid->memaddr = vid->memaddr_backup; + } + if (vid->scanline == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->scanline == ((vid->crtc[10] & 31) >> 1))) + vid->cursorvisible = 1; + } +} + +void +tandy_vid_speed_changed(void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + + recalc_timings(dev); +} + +void +tandy_vid_close(void *priv) +{ + tandy_t *dev = (tandy_t *) priv; + + free(dev->vid); + dev->vid = NULL; +} + +void +tandy_vid_init(tandy_t *dev) +{ + int display_type; + t1kvid_t *vid; + + vid = calloc(1, sizeof(t1kvid_t)); + vid->memctrl = -1; + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_dram); + + display_type = device_get_config_int("display_type"); + vid->composite = (display_type != TANDY_RGB); + + cga_comp_init(1); + + if (dev->is_sl2) { + vid->b8000_limit = 0x8000; + vid->planar_ctrl = 4; + overscan_x = overscan_y = 16; + + io_sethandler(0x0065, 1, tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); + } else + vid->b8000_mask = 0x3fff; + + timer_add(&vid->timer, vid_poll, dev, 1); + mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, + vid_read, NULL, NULL, vid_write, NULL, NULL, NULL, 0, dev); + io_sethandler(0x03d0, 16, + tandy_vid_in, NULL, NULL, tandy_vid_out, NULL, NULL, dev); + + dev->vid = vid; +} + +const device_config_t vid_config[] = { + // clang-format off + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .default_string = "", + .default_int = TANDY_RGB, + .file_filter = "", + .spinner = { 0 }, + .selection = { + { .description = "RGB", .value = TANDY_RGB }, + { .description = "Composite", .value = TANDY_COMPOSITE }, + { .description = "" } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t tandy_1000_video_device = { + .name = "Tandy 1000", + .internal_name = "tandy1000_video", + .flags = 0, + .local = 0, + .init = NULL, + .close = tandy_vid_close, + .reset = NULL, + .available = NULL, + .speed_changed = tandy_vid_speed_changed, + .force_redraw = NULL, + .config = vid_config +}; + +const device_t tandy_1000hx_video_device = { + .name = "Tandy 1000 HX", + .internal_name = "tandy1000_hx_video", + .flags = 0, + .local = 0, + .init = NULL, + .close = tandy_vid_close, + .reset = NULL, + .available = NULL, + .speed_changed = tandy_vid_speed_changed, + .force_redraw = NULL, + .config = vid_config +}; + +const device_t tandy_1000sl_video_device = { + .name = "Tandy 1000SL2", + .internal_name = "tandy1000_sl_video", + .flags = 0, + .local = 1, + .init = NULL, + .close = tandy_vid_close, + .reset = NULL, + .available = NULL, + .speed_changed = tandy_vid_speed_changed, + .force_redraw = NULL, + .config = NULL +}; diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 6fbdb7c3f..5cc3a8a78 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -543,7 +543,7 @@ tgui_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = svga->monitor->mon_changeframecount; svga_recalctimings(svga); @@ -726,13 +726,13 @@ tgui_recalctimings(svga_t *svga) #endif if ((svga->crtc[0x1e] & 0xA0) == 0xA0) - svga->ma_latch |= 0x10000; + svga->memaddr_latch |= 0x10000; if (svga->crtc[0x27] & 0x01) - svga->ma_latch |= 0x20000; + svga->memaddr_latch |= 0x20000; if (svga->crtc[0x27] & 0x02) - svga->ma_latch |= 0x40000; + svga->memaddr_latch |= 0x40000; if (svga->crtc[0x27] & 0x04) - svga->ma_latch |= 0x80000; + svga->memaddr_latch |= 0x80000; if (svga->crtc[0x27] & 0x08) svga->split |= 0x400; @@ -759,7 +759,7 @@ tgui_recalctimings(svga_t *svga) svga->vdisp += 2; if (tgui->oldctrl2 & 0x10) - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; svga->lowres = !(svga->crtc[0x2a] & 0x40); diff --git a/src/video/vid_tvga.c b/src/video/vid_tvga.c index 9dd7e424d..51ab132ca 100644 --- a/src/video/vid_tvga.c +++ b/src/video/vid_tvga.c @@ -168,7 +168,7 @@ tvga_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -293,15 +293,15 @@ tvga_recalctimings(svga_t *svga) svga->hdisp = (svga->crtc[1] + 1) * 8; if ((svga->crtc[0x1e] & 0xA0) == 0xA0) - svga->ma_latch |= 0x10000; + svga->memaddr_latch |= 0x10000; if ((svga->crtc[0x27] & 0x01) == 0x01) - svga->ma_latch |= 0x20000; + svga->memaddr_latch |= 0x20000; if ((svga->crtc[0x27] & 0x02) == 0x02) - svga->ma_latch |= 0x40000; + svga->memaddr_latch |= 0x40000; if (tvga->oldctrl2 & 0x10) { svga->rowoffset <<= 1; - svga->ma_latch <<= 1; + svga->memaddr_latch <<= 1; } if (svga->gdcreg[0xf] & 0x08) { diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 8289fd4cb..4cde5ba01 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -63,7 +63,7 @@ vga_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index 8f6e8bf26..f922fb990 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -530,6 +530,7 @@ voodoo_writel(uint32_t addr, uint32_t val, void *priv) voodoo_recalc(voodoo); voodoo->front_offset = voodoo->params.front_offset; } + svga_recalctimings(voodoo->svga); } break; case SST_fbiInit1: diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 1381a95f7..4bcf8a479 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -385,7 +385,7 @@ banshee_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x11 || (svga->crtcreg == 0x11 && old != val)) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -663,7 +663,7 @@ banshee_recalctimings(svga_t *svga) svga->rowoffset = ((banshee->vidDesktopOverlayStride & 0x3fff) * 128) >> 3; else svga->rowoffset = (banshee->vidDesktopOverlayStride & 0x3fff) >> 3; - svga->ma_latch = banshee->vidDesktopStartAddr >> 2; + svga->memaddr_latch = banshee->vidDesktopStartAddr >> 2; banshee->desktop_stride_tiled = (banshee->vidDesktopOverlayStride & 0x3fff) * 128 * 32; #if 0 banshee_log("Extended shift out %i rowoffset=%i %02x\n", VIDPROCCFG_DESKTOP_PIX_FORMAT, svga->rowoffset, svga->crtc[1]); diff --git a/src/video/vid_wy700.c b/src/video/vid_wy700.c index a52bad4ee..c00541113 100644 --- a/src/video/vid_wy700.c +++ b/src/video/vid_wy700.c @@ -212,9 +212,9 @@ typedef struct wy700_t { } wy700_t; /* Mapping of attributes to colours, in CGA emulation... */ -static int cgacols[256][2][2]; +static int cga_attr_to_color_table[256][2][2]; /* ... and MDA emulation. */ -static int mdacols[256][2][2]; +static int mda_attr_to_color_table[256][2][2]; void wy700_recalctimings(wy700_t *wy700); void wy700_write(uint32_t addr, uint8_t val, void *priv); @@ -535,9 +535,9 @@ wy700_textline(wy700_t *wy700) int cursorline; int mda = 0; uint16_t addr; - uint8_t sc; - uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; - uint16_t ca = (wy700->cga_crtc[15] | (wy700->cga_crtc[14] << 8)) & 0x3fff; + uint8_t scanline; + uint16_t memaddr = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; + uint16_t cursoraddr = (wy700->cga_crtc[15] | (wy700->cga_crtc[14] << 8)) & 0x3fff; /* The fake CRTC character height register selects whether MDA or CGA * attributes are used */ @@ -548,41 +548,41 @@ wy700_textline(wy700_t *wy700) if (wy700->font) { fontbase += 256 * 32; } - addr = ((ma & ~1) + (wy700->displine >> 5) * w) * 2; - sc = (wy700->displine >> 1) & 15; + addr = ((memaddr & ~1) + (wy700->displine >> 5) * w) * 2; + scanline = (wy700->displine >> 1) & 15; - ma += ((wy700->displine >> 5) * w); + memaddr += ((wy700->displine >> 5) * w); if ((wy700->real_crtc[10] & 0x60) == 0x20) { cursorline = 0; } else { - cursorline = ((wy700->real_crtc[10] & 0x1F) <= sc) && ((wy700->real_crtc[11] & 0x1F) >= sc); + cursorline = ((wy700->real_crtc[10] & 0x1F) <= scanline) && ((wy700->real_crtc[11] & 0x1F) >= scanline); } for (int x = 0; x < w; x++) { chr = wy700->vram[(addr + 2 * x) & 0x3FFF]; attr = wy700->vram[(addr + 2 * x + 1) & 0x3FFF]; - drawcursor = ((ma == ca) && cursorline && wy700->enabled && (wy700->cga_ctrl & 8) && (wy700->blink & 16)); + drawcursor = ((memaddr == cursoraddr) && cursorline && wy700->enabled && (wy700->cga_ctrl & 8) && (wy700->blink & 16)); blink = ((wy700->blink & 16) && (wy700->cga_ctrl & 0x20) && (attr & 0x80) && !drawcursor); if (wy700->cga_ctrl & 0x20) attr &= 0x7F; /* MDA underline */ - if (sc == 14 && mda && ((attr & 7) == 1)) { + if (scanline == 14 && mda && ((attr & 7) == 1)) { for (c = 0; c < cw; c++) - buffer32->line[wy700->displine][(x * cw) + c] = mdacols[attr][blink][1]; + buffer32->line[wy700->displine][(x * cw) + c] = mda_attr_to_color_table[attr][blink][1]; } else /* Draw 16 pixels of character */ { - bitmap[0] = fontbase[chr * 32 + 2 * sc]; - bitmap[1] = fontbase[chr * 32 + 2 * sc + 1]; + bitmap[0] = fontbase[chr * 32 + 2 * scanline]; + bitmap[1] = fontbase[chr * 32 + 2 * scanline + 1]; for (c = 0; c < 16; c++) { int col; if (c < 8) - col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + col = (mda ? mda_attr_to_color_table : cga_attr_to_color_table)[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; else - col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[1] & (1 << ((c & 7) ^ 7))) ? 1 : 0]; + col = (mda ? mda_attr_to_color_table : cga_attr_to_color_table)[attr][blink][(bitmap[1] & (1 << ((c & 7) ^ 7))) ? 1 : 0]; if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) - col = mdacols[0][0][0]; + col = mda_attr_to_color_table[0][0][0]; if (w == 40) { buffer32->line[wy700->displine][(x * cw) + 2 * c] = col; buffer32->line[wy700->displine][(x * cw) + 2 * c + 1] = col; @@ -592,9 +592,9 @@ wy700_textline(wy700_t *wy700) if (drawcursor) { for (c = 0; c < cw; c++) - buffer32->line[wy700->displine][(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; + buffer32->line[wy700->displine][(x * cw) + c] ^= (mda ? mda_attr_to_color_table : cga_attr_to_color_table)[attr][0][1]; } - ++ma; + ++memaddr; } } } @@ -608,8 +608,8 @@ wy700_cgaline(wy700_t *wy700) uint8_t ink = 0; uint16_t addr; - uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; - addr = ((wy700->displine >> 2) & 1) * 0x2000 + (wy700->displine >> 3) * 80 + ((ma & ~1) << 1); + uint16_t memaddr = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; + addr = ((wy700->displine >> 2) & 1) * 0x2000 + (wy700->displine >> 3) * 80 + ((memaddr & ~1) << 1); /* The fixed mode setting here programs the real CRTC with a screen * width to 20, so draw in 20 fixed chunks of 4 bytes each */ @@ -902,74 +902,74 @@ wy700_init(UNUSED(const device_t *info)) /* Set up the emulated attributes. * CGA is done in four groups: 00-0F, 10-7F, 80-8F, 90-FF */ for (c = 0; c < 0x10; c++) { - cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16; + cga_attr_to_color_table[c][0][0] = cga_attr_to_color_table[c][1][0] = cga_attr_to_color_table[c][1][1] = 16; if (c & 8) - cgacols[c][0][1] = 15 + 16; + cga_attr_to_color_table[c][0][1] = 15 + 16; else - cgacols[c][0][1] = 7 + 16; + cga_attr_to_color_table[c][0][1] = 7 + 16; } for (c = 0x10; c < 0x80; c++) { - cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16 + 7; + cga_attr_to_color_table[c][0][0] = cga_attr_to_color_table[c][1][0] = cga_attr_to_color_table[c][1][1] = 16 + 7; if (c & 8) - cgacols[c][0][1] = 15 + 16; + cga_attr_to_color_table[c][0][1] = 15 + 16; else - cgacols[c][0][1] = 0 + 16; + cga_attr_to_color_table[c][0][1] = 0 + 16; if ((c & 0x0F) == 8) - cgacols[c][0][1] = 8 + 16; + cga_attr_to_color_table[c][0][1] = 8 + 16; } /* With special cases for 00, 11, 22, ... 77 */ - cgacols[0x00][0][1] = cgacols[0x00][1][1] = 16; + cga_attr_to_color_table[0x00][0][1] = cga_attr_to_color_table[0x00][1][1] = 16; for (c = 0x11; c <= 0x77; c += 0x11) { - cgacols[c][0][1] = cgacols[c][1][1] = 16 + 7; + cga_attr_to_color_table[c][0][1] = cga_attr_to_color_table[c][1][1] = 16 + 7; } for (c = 0x80; c < 0x90; c++) { - cgacols[c][0][0] = 16 + 8; + cga_attr_to_color_table[c][0][0] = 16 + 8; if (c & 8) - cgacols[c][0][1] = 15 + 16; + cga_attr_to_color_table[c][0][1] = 15 + 16; else - cgacols[c][0][1] = 7 + 16; - cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c - 0x80][0][0]; + cga_attr_to_color_table[c][0][1] = 7 + 16; + cga_attr_to_color_table[c][1][0] = cga_attr_to_color_table[c][1][1] = cga_attr_to_color_table[c - 0x80][0][0]; } for (c = 0x90; c < 0x100; c++) { - cgacols[c][0][0] = 16 + 15; + cga_attr_to_color_table[c][0][0] = 16 + 15; if (c & 8) - cgacols[c][0][1] = 8 + 16; + cga_attr_to_color_table[c][0][1] = 8 + 16; else - cgacols[c][0][1] = 7 + 16; + cga_attr_to_color_table[c][0][1] = 7 + 16; if ((c & 0x0F) == 0) - cgacols[c][0][1] = 16; - cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c - 0x80][0][0]; + cga_attr_to_color_table[c][0][1] = 16; + cga_attr_to_color_table[c][1][0] = cga_attr_to_color_table[c][1][1] = cga_attr_to_color_table[c - 0x80][0][0]; } /* Also special cases for 99, AA, ..., FF */ for (c = 0x99; c <= 0xFF; c += 0x11) { - cgacols[c][0][1] = 16 + 15; + cga_attr_to_color_table[c][0][1] = 16 + 15; } /* Special cases for 08, 80 and 88 */ - cgacols[0x08][0][1] = 16 + 8; - cgacols[0x80][0][1] = 16; - cgacols[0x88][0][1] = 16 + 8; + cga_attr_to_color_table[0x08][0][1] = 16 + 8; + cga_attr_to_color_table[0x80][0][1] = 16; + cga_attr_to_color_table[0x88][0][1] = 16 + 8; /* MDA attributes */ for (c = 0; c < 256; c++) { - mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + mda_attr_to_color_table[c][0][0] = mda_attr_to_color_table[c][1][0] = mda_attr_to_color_table[c][1][1] = 16; if (c & 8) - mdacols[c][0][1] = 15 + 16; + mda_attr_to_color_table[c][0][1] = 15 + 16; else - mdacols[c][0][1] = 7 + 16; + mda_attr_to_color_table[c][0][1] = 7 + 16; } - mdacols[0x70][0][1] = 16; - mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; - mdacols[0xF0][0][1] = 16; - mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; - mdacols[0x78][0][1] = 16 + 7; - mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; - mdacols[0xF8][0][1] = 16 + 7; - mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; - mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; - mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; - mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; - mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + mda_attr_to_color_table[0x70][0][1] = 16; + mda_attr_to_color_table[0x70][0][0] = mda_attr_to_color_table[0x70][1][0] = mda_attr_to_color_table[0x70][1][1] = 16 + 15; + mda_attr_to_color_table[0xF0][0][1] = 16; + mda_attr_to_color_table[0xF0][0][0] = mda_attr_to_color_table[0xF0][1][0] = mda_attr_to_color_table[0xF0][1][1] = 16 + 15; + mda_attr_to_color_table[0x78][0][1] = 16 + 7; + mda_attr_to_color_table[0x78][0][0] = mda_attr_to_color_table[0x78][1][0] = mda_attr_to_color_table[0x78][1][1] = 16 + 15; + mda_attr_to_color_table[0xF8][0][1] = 16 + 7; + mda_attr_to_color_table[0xF8][0][0] = mda_attr_to_color_table[0xF8][1][0] = mda_attr_to_color_table[0xF8][1][1] = 16 + 15; + mda_attr_to_color_table[0x00][0][1] = mda_attr_to_color_table[0x00][1][1] = 16; + mda_attr_to_color_table[0x08][0][1] = mda_attr_to_color_table[0x08][1][1] = 16; + mda_attr_to_color_table[0x80][0][1] = mda_attr_to_color_table[0x80][1][1] = 16; + mda_attr_to_color_table[0x88][0][1] = mda_attr_to_color_table[0x88][1][1] = 16; /* Start off in 80x25 text mode */ wy700->cga_stat = 0xF4; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 4c08b7b71..8f4dc0d0e 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -107,7 +107,7 @@ svga_xga_out(uint16_t addr, uint8_t val, void *priv) if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { if ((svga->crtcreg == 0xc) || (svga->crtcreg == 0xd)) { svga->fullchange = 3; - svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->memaddr_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); } else { svga->fullchange = changeframecount; svga_recalctimings(svga); @@ -290,7 +290,7 @@ xga_recalctimings(svga_t *svga) xga->v_blankstart >>= 1; } - xga->ma_latch = xga->disp_start_addr; + xga->memaddr_latch = xga->disp_start_addr; xga_log("XGA ClkSel1 = %d, ClkSel2 = %02x, dispcntl2=%02x.\n", (xga->clk_sel_1 >> 2) & 3, xga->clk_sel_2 & 0x80, xga->disp_cntl_2 & 0xc0); @@ -2626,7 +2626,7 @@ xga_render_4bpp(svga_t *svga) if ((xga->displine + svga->y_add) < 0) return; - if (xga->changedvram[xga->ma >> 12] || xga->changedvram[(xga->ma >> 12) + 1] || svga->fullchange) { + if (xga->changedvram[xga->memaddr >> 12] || xga->changedvram[(xga->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[xga->displine + svga->y_add][svga->x_add]; if (xga->firstline_draw == 2000) @@ -2635,22 +2635,22 @@ xga_render_4bpp(svga_t *svga) xga->lastline_draw = xga->displine; for (int x = 0; x <= xga->h_disp; x += 8) { - dat = *(uint32_t *) (&xga->vram[xga->ma & xga->vram_mask]); + dat = *(uint32_t *) (&xga->vram[xga->memaddr & xga->vram_mask]); p[0] = xga->pallook[dat & 0x0f]; p[1] = xga->pallook[(dat >> 8) & 0x0f]; p[2] = xga->pallook[(dat >> 16) & 0x0f]; p[3] = xga->pallook[(dat >> 24) & 0x0f]; - dat = *(uint32_t *) (&xga->vram[(xga->ma + 2) & xga->vram_mask]); + dat = *(uint32_t *) (&xga->vram[(xga->memaddr + 2) & xga->vram_mask]); p[4] = xga->pallook[dat & 0x0f]; p[5] = xga->pallook[(dat >> 8) & 0x0f]; p[6] = xga->pallook[(dat >> 16) & 0x0f]; p[7] = xga->pallook[(dat >> 24) & 0x0f]; - xga->ma += 8; + xga->memaddr += 8; p += 8; } - xga->ma &= xga->vram_mask; + xga->memaddr &= xga->vram_mask; } } @@ -2664,7 +2664,7 @@ xga_render_8bpp(svga_t *svga) if ((xga->displine + svga->y_add) < 0) return; - if (xga->changedvram[xga->ma >> 12] || xga->changedvram[(xga->ma >> 12) + 1] || svga->fullchange) { + if (xga->changedvram[xga->memaddr >> 12] || xga->changedvram[(xga->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[xga->displine + svga->y_add][svga->x_add]; if (xga->firstline_draw == 2000) @@ -2672,22 +2672,22 @@ xga_render_8bpp(svga_t *svga) xga->lastline_draw = xga->displine; for (int x = 0; x <= xga->h_disp; x += 8) { - dat = *(uint32_t *) (&xga->vram[xga->ma & xga->vram_mask]); + dat = *(uint32_t *) (&xga->vram[xga->memaddr & xga->vram_mask]); p[0] = xga->pallook[dat & 0xff]; p[1] = xga->pallook[(dat >> 8) & 0xff]; p[2] = xga->pallook[(dat >> 16) & 0xff]; p[3] = xga->pallook[(dat >> 24) & 0xff]; - dat = *(uint32_t *) (&xga->vram[(xga->ma + 4) & xga->vram_mask]); + dat = *(uint32_t *) (&xga->vram[(xga->memaddr + 4) & xga->vram_mask]); p[4] = xga->pallook[dat & 0xff]; p[5] = xga->pallook[(dat >> 8) & 0xff]; p[6] = xga->pallook[(dat >> 16) & 0xff]; p[7] = xga->pallook[(dat >> 24) & 0xff]; - xga->ma += 8; + xga->memaddr += 8; p += 8; } - xga->ma &= xga->vram_mask; + xga->memaddr &= xga->vram_mask; } } @@ -2702,7 +2702,7 @@ xga_render_16bpp(svga_t *svga) if ((xga->displine + svga->y_add) < 0) return; - if (xga->changedvram[xga->ma >> 12] || xga->changedvram[(xga->ma >> 12) + 1] || svga->fullchange) { + if (xga->changedvram[xga->memaddr >> 12] || xga->changedvram[(xga->memaddr >> 12) + 1] || svga->fullchange) { p = &buffer32->line[xga->displine + svga->y_add][svga->x_add]; if (xga->firstline_draw == 2000) @@ -2710,24 +2710,24 @@ xga_render_16bpp(svga_t *svga) xga->lastline_draw = xga->displine; for (x = 0; x <= xga->h_disp; x += 8) { - dat = *(uint32_t *) (&xga->vram[(xga->ma + (x << 1)) & xga->vram_mask]); + dat = *(uint32_t *) (&xga->vram[(xga->memaddr + (x << 1)) & xga->vram_mask]); p[x] = video_16to32[dat & 0xffff]; p[x + 1] = video_16to32[dat >> 16]; - dat = *(uint32_t *) (&xga->vram[(xga->ma + (x << 1) + 4) & xga->vram_mask]); + dat = *(uint32_t *) (&xga->vram[(xga->memaddr + (x << 1) + 4) & xga->vram_mask]); p[x + 2] = video_16to32[dat & 0xffff]; p[x + 3] = video_16to32[dat >> 16]; - dat = *(uint32_t *) (&xga->vram[(xga->ma + (x << 1) + 8) & xga->vram_mask]); + dat = *(uint32_t *) (&xga->vram[(xga->memaddr + (x << 1) + 8) & xga->vram_mask]); p[x + 4] = video_16to32[dat & 0xffff]; p[x + 5] = video_16to32[dat >> 16]; - dat = *(uint32_t *) (&xga->vram[(xga->ma + (x << 1) + 12) & xga->vram_mask]); + dat = *(uint32_t *) (&xga->vram[(xga->memaddr + (x << 1) + 12) & xga->vram_mask]); p[x + 6] = video_16to32[dat & 0xffff]; p[x + 7] = video_16to32[dat >> 16]; } - xga->ma += x << 1; - xga->ma &= xga->vram_mask; + xga->memaddr += x << 1; + xga->memaddr &= xga->vram_mask; } } @@ -3109,7 +3109,7 @@ xga_poll(void *priv) if (xga->dispon) { xga->h_disp_on = 1; - xga->ma &= xga->vram_mask; + xga->memaddr &= xga->vram_mask; if (xga->firstline == 2000) { xga->firstline = xga->displine; @@ -3117,7 +3117,7 @@ xga_poll(void *priv) } if (xga->hwcursor_on) - xga->changedvram[xga->ma >> 12] = xga->changedvram[(xga->ma >> 12) + 1] = xga->interlace ? 3 : 2; + xga->changedvram[xga->memaddr >> 12] = xga->changedvram[(xga->memaddr >> 12) + 1] = xga->interlace ? 3 : 2; svga->render_xga(svga); @@ -3153,20 +3153,20 @@ xga_poll(void *priv) xga->linepos = 0; if (xga->dispon) { - if (xga->sc == xga->rowcount) { - xga->sc = 0; + if (xga->scanline == xga->rowcount) { + xga->scanline = 0; - xga_log("MA=%08x, MALATCH=%x.\n", xga->ma, xga->ma_latch); - xga->maback += (xga->rowoffset << 3); + xga_log("MA=%08x, MALATCH=%x.\n", xga->memaddr, xga->memaddr_latch); + xga->memaddr_backup += (xga->rowoffset << 3); if (xga->interlace) - xga->maback += (xga->rowoffset << 3); + xga->memaddr_backup += (xga->rowoffset << 3); - xga->maback &= xga->vram_mask; - xga->ma = xga->maback; + xga->memaddr_backup &= xga->vram_mask; + xga->memaddr = xga->memaddr_backup; } else { - xga->sc++; - xga->sc &= 0x1f; - xga->ma = xga->maback; + xga->scanline++; + xga->scanline &= 0x1f; + xga->memaddr = xga->memaddr_backup; } } @@ -3175,14 +3175,14 @@ xga_poll(void *priv) if (xga->vc == xga->split) { if (xga->interlace && xga->oddeven) - xga->ma = xga->maback = (xga->rowoffset << 1); + xga->memaddr = xga->memaddr_backup = (xga->rowoffset << 1); else - xga->ma = xga->maback = 0; + xga->memaddr = xga->memaddr_backup = 0; - xga->ma = (xga->ma << 2); - xga->maback = (xga->maback << 2); + xga->memaddr = (xga->memaddr << 2); + xga->memaddr_backup = (xga->memaddr_backup << 2); - xga->sc = 0; + xga->scanline = 0; } if (xga->vc == xga->dispend) { xga->dispon = 0; @@ -3220,16 +3220,16 @@ xga_poll(void *priv) svga->monitor->mon_changeframecount = xga->interlace ? 3 : 2; if (xga->interlace && xga->oddeven) - xga->ma = xga->maback = xga->ma_latch + (xga->rowoffset << 1); + xga->memaddr = xga->memaddr_backup = xga->memaddr_latch + (xga->rowoffset << 1); else - xga->ma = xga->maback = xga->ma_latch; + xga->memaddr = xga->memaddr_backup = xga->memaddr_latch; - xga->ma = (xga->ma << 2); - xga->maback = (xga->maback << 2); + xga->memaddr = (xga->memaddr << 2); + xga->memaddr_backup = (xga->memaddr_backup << 2); } if (xga->vc == xga->v_total) { xga->vc = 0; - xga->sc = 0; + xga->scanline = 0; xga->dispon = 1; xga->displine = (xga->interlace && xga->oddeven) ? 1 : 0;