diff --git a/src/chipset/opti283.c b/src/chipset/opti283.c index 1fa59f2f0..63976985b 100644 --- a/src/chipset/opti283.c +++ b/src/chipset/opti283.c @@ -31,6 +31,7 @@ #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_OPTI283_LOG @@ -215,16 +216,27 @@ opti283_write(uint16_t addr, uint8_t val, void *priv) opti283_t *dev = (opti283_t *) priv; switch (addr) { + default: + break; + case 0x22: dev->index = val; break; + case 0x23: + if (dev->index == 0x01) + dev->regs[dev->index] = val; + break; + case 0x24: opti283_log("OPTi 283: dev->regs[%02x] = %02x\n", dev->index, val); switch (dev->index) { + default: + break; + case 0x10: - dev->regs[dev->index] = val; + dev->regs[dev->index] = (dev->regs[dev->index] & 0x80) | (val & 0x7f); break; case 0x14: @@ -236,13 +248,9 @@ opti283_write(uint16_t addr, uint8_t val, void *priv) dev->regs[dev->index] = val; opti283_shadow_recalc(dev); break; - - default: - break; } - break; - default: + dev->index = 0xff; break; } } @@ -250,11 +258,17 @@ opti283_write(uint16_t addr, uint8_t val, void *priv) static uint8_t opti283_read(uint16_t addr, void *priv) { - const opti283_t *dev = (opti283_t *) priv; - uint8_t ret = 0xff; + opti283_t *dev = (opti283_t *) priv; + uint8_t ret = 0xff; - if (addr == 0x24) + if ((addr == 0x23) && (dev->index == 0x01)) ret = dev->regs[dev->index]; + else if (addr == 0x24) { + if ((dev->index >= 0x10) && (dev->index <= 0x14)) + ret = dev->regs[dev->index]; + + dev->index = 0xff; + } return ret; } @@ -274,6 +288,7 @@ opti283_init(UNUSED(const device_t *info)) memset(dev, 0x00, sizeof(opti283_t)); io_sethandler(0x0022, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); + io_sethandler(0x0023, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); io_sethandler(0x0024, 0x0001, opti283_read, NULL, NULL, opti283_write, NULL, NULL, dev); dev->regs[0x10] = 0x3f; @@ -296,6 +311,8 @@ opti283_init(UNUSED(const device_t *info)) opti283_shadow_recalc(dev); + device_add(&port_92_device); + return dev; } diff --git a/src/chipset/opti391.c b/src/chipset/opti391.c index c4c5534f8..c22c2a04b 100644 --- a/src/chipset/opti391.c +++ b/src/chipset/opti391.c @@ -178,6 +178,9 @@ opti391_write(uint16_t addr, uint8_t val, void *priv) opti391_log("[W] %04X = %02X\n", addr, val); switch (addr) { + default: + break; + case 0x22: dev->index = val; break; @@ -200,6 +203,9 @@ opti391_write(uint16_t addr, uint8_t val, void *priv) reset_on_hlt = !!(val & 0x02); break; } else switch (dev->index - dev->reg_base) { + default: + break; + case 0x00: if (dev->type == 2) { reset_on_hlt = !!(val & 0x02); @@ -222,8 +228,14 @@ opti391_write(uint16_t addr, uint8_t val, void *priv) opti391_recalcremap(dev); break; - case 0x04: case 0x05: + if (dev->type == 2) + dev->regs[dev->index - dev->reg_base] = val & 0xf8; + else + dev->regs[dev->index - dev->reg_base] = val; + break; + + case 0x04: case 0x09: case 0x0a: case 0x0b: @@ -238,8 +250,10 @@ opti391_write(uint16_t addr, uint8_t val, void *priv) } break; case 0x08: - dev->regs[dev->index - dev->reg_base] = val; - if (dev->type < 2) { + if (dev->type == 2) + dev->regs[dev->index - dev->reg_base] = val & 0xe3; + else { + dev->regs[dev->index - dev->reg_base] = val; cpu_cache_ext_enabled = !!(dev->regs[0x02] & 0x40); cpu_update_waitstates(); } @@ -257,13 +271,9 @@ opti391_write(uint16_t addr, uint8_t val, void *priv) dev->regs[dev->index - dev->reg_base] = val; opti391_shadow_recalc(dev); break; - - default: - break; } - break; - default: + dev->index = 0xff; break; } } @@ -271,14 +281,16 @@ opti391_write(uint16_t addr, uint8_t val, void *priv) static uint8_t opti391_read(uint16_t addr, void *priv) { - const opti391_t *dev = (opti391_t *) priv; - uint8_t ret = 0xff; + opti391_t *dev = (opti391_t *) priv; + uint8_t ret = 0xff; if (addr == 0x24) { if ((dev->index <= 0x01) && (dev->type < 2)) ret = dev->regs[dev->index + 0x10]; else if ((dev->index >= dev->min_reg) && (dev->index <= dev->max_reg)) ret = dev->regs[dev->index - dev->reg_base]; + + dev->index = 0xff; } opti391_log("[R] %04X = %02X\n", addr, ret); diff --git a/src/chipset/opti495.c b/src/chipset/opti495.c index 13bc2a124..84ef6a202 100644 --- a/src/chipset/opti495.c +++ b/src/chipset/opti495.c @@ -32,6 +32,8 @@ #include <86box/chipset.h> typedef struct opti495_t { + uint8_t type; + uint8_t max; uint8_t idx; uint8_t regs[256]; uint8_t scratch[2]; @@ -55,6 +57,22 @@ opti495_log(const char *fmt, ...) # define opti495_log(fmt, ...) #endif +enum { + OPTI493 = 0, + OPTI495, + OPTI495SLC, + OPTI495SX, + OPTI495XLC, + TMAX +}; + +/* OPTi 82C493: According to The Last Byte, bit 1 of register 22h, while unused, must still be writable. */ +static uint8_t masks[TMAX][0x1c] = { { 0x3f, 0xff, 0xff, 0xff, 0xf7, 0xfb, 0x7f, 0x9f, 0xe3, 0xff, 0xe3, 0xff }, + { 0x3a, 0x7f, 0xff, 0xff, 0xf0, 0xfb, 0x7f, 0xbf, 0xe3, 0xff, 0x00, 0x00 }, + { 0x3a, 0x7f, 0xfc, 0xff, 0xf0, 0xfb, 0xff, 0xbf, 0xe3, 0xff, 0x00, 0x00 }, + { 0x3a, 0xff, 0xfd, 0xff, 0xf0, 0xfb, 0x7f, 0xbf, 0xe3, 0xff, 0x00, 0x00 }, + { 0x3a, 0xff, 0xfc, 0xff, 0xf0, 0xfb, 0xff, 0xbf, 0xe3, 0xff, 0x00, 0x00 } }; + static void opti495_recalc(opti495_t *dev) { @@ -119,16 +137,25 @@ opti495_write(uint16_t addr, uint8_t val, void *priv) opti495_t *dev = (opti495_t *) priv; switch (addr) { + default: + break; + case 0x22: opti495_log("[%04X:%08X] [W] dev->idx = %02X\n", CS, cpu_state.pc, val); dev->idx = val; break; case 0x24: - if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { - dev->regs[dev->idx] = val; + if ((dev->idx >= 0x20) && (dev->idx <= dev->max)) { opti495_log("[%04X:%08X] [W] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, val); + dev->regs[dev->idx] = val & masks[dev->type][dev->idx - 0x20]; + if ((dev->type == OPTI493) && (dev->idx == 0x20)) + val |= 0x40; + switch (dev->idx) { + default: + break; + case 0x21: cpu_cache_ext_enabled = !!(dev->regs[0x21] & 0x10); cpu_update_waitstates(); @@ -139,36 +166,36 @@ opti495_write(uint16_t addr, uint8_t val, void *priv) case 0x26: opti495_recalc(dev); break; - default: - break; } } + + dev->idx = 0xff; break; case 0xe1: case 0xe2: dev->scratch[~addr & 0x01] = val; break; - default: - break; } } static uint8_t opti495_read(uint16_t addr, void *priv) { - uint8_t ret = 0xff; - const opti495_t *dev = (opti495_t *) priv; + uint8_t ret = 0xff; + opti495_t *dev = (opti495_t *) priv; switch (addr) { case 0x22: opti495_log("[%04X:%08X] [R] dev->idx = %02X\n", CS, cpu_state.pc, ret); break; case 0x24: - if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { + if ((dev->idx >= 0x20) && (dev->idx <= dev->max)) { ret = dev->regs[dev->idx]; opti495_log("[%04X:%08X] [R] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, ret); } + + dev->idx = 0xff; break; case 0xe1: case 0xe2: @@ -202,8 +229,11 @@ opti495_init(const device_t *info) dev->scratch[0] = dev->scratch[1] = 0xff; - if (info->local == 1) { + dev->type = info->local; + + if (info->local >= OPTI495) { /* 85C495 */ + dev->max = 0x29; dev->regs[0x20] = 0x02; dev->regs[0x21] = 0x20; dev->regs[0x22] = 0xe4; @@ -214,6 +244,7 @@ opti495_init(const device_t *info) dev->regs[0x29] = 0x10; } else { /* 85C493 */ + dev->max = 0x2b; dev->regs[0x20] = 0x40; dev->regs[0x22] = 0x84; dev->regs[0x24] = 0x87; @@ -236,7 +267,7 @@ const device_t opti493_device = { .name = "OPTi 82C493", .internal_name = "opti493", .flags = 0, - .local = 0, + .local = OPTI493, .init = opti495_init, .close = opti495_close, .reset = NULL, @@ -250,7 +281,7 @@ const device_t opti495_device = { .name = "OPTi 82C495", .internal_name = "opti495", .flags = 0, - .local = 1, + .local = OPTI495XLC, .init = opti495_init, .close = opti495_close, .reset = NULL, diff --git a/src/chipset/opti499.c b/src/chipset/opti499.c index d976e0198..ecadd2224 100644 --- a/src/chipset/opti499.c +++ b/src/chipset/opti499.c @@ -38,6 +38,9 @@ typedef struct opti499_t { uint8_t scratch[2]; } opti499_t; +/* According to The Last Byte, register 2Dh bit 7 must still be writable, even if it is unused. */ +static uint8_t masks[0x0e] = { 0x3f, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xfb, 0xff, 0x00, 0xff }; + #ifdef ENABLE_OPTI499_LOG int opti499_do_log = ENABLE_OPTI499_LOG; @@ -126,19 +129,25 @@ opti499_write(uint16_t addr, uint8_t val, void *priv) opti499_t *dev = (opti499_t *) priv; switch (addr) { + default: + break; + case 0x22: opti499_log("[%04X:%08X] [W] dev->idx = %02X\n", CS, cpu_state.pc, val); dev->idx = val; break; case 0x24: - if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { - if (dev->idx == 0x20) - dev->regs[dev->idx] = (dev->regs[dev->idx] & 0xc0) | (val & 0x3f); - else - dev->regs[dev->idx] = val; + if ((dev->idx >= 0x20) && (dev->idx <= 0x2d) && (dev->idx != 0x2c)) { opti499_log("[%04X:%08X] [W] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, val); + dev->regs[dev->idx] = val & masks[dev->idx - 0x20]; + if (dev->idx == 0x2a) + dev->regs[dev->idx] |= 0x04; + switch (dev->idx) { + default: + break; + case 0x20: reset_on_hlt = !(val & 0x02); break; @@ -154,20 +163,16 @@ opti499_write(uint16_t addr, uint8_t val, void *priv) case 0x2d: opti499_recalc(dev); break; - - default: - break; } } + + dev->idx = 0xff; break; case 0xe1: case 0xe2: dev->scratch[~addr & 0x01] = val; break; - - default: - break; } } @@ -178,25 +183,23 @@ opti499_read(uint16_t addr, void *priv) opti499_t *dev = (opti499_t *) priv; switch (addr) { + default: + break; + case 0x22: opti499_log("[%04X:%08X] [R] dev->idx = %02X\n", CS, cpu_state.pc, ret); break; case 0x24: - if ((dev->idx >= 0x20) && (dev->idx <= 0x2d)) { - if (dev->idx == 0x2d) - ret = dev->regs[dev->idx] & 0xbf; - else - ret = dev->regs[dev->idx]; + if ((dev->idx >= 0x20) && (dev->idx <= 0x2d) && (dev->idx != 0x2c)) { + ret = dev->regs[dev->idx]; opti499_log("[%04X:%08X] [R] dev->regs[%04X] = %02X\n", CS, cpu_state.pc, dev->idx, ret); } + dev->idx = 0xff; break; case 0xe1: case 0xe2: ret = dev->scratch[~addr & 0x01]; break; - - default: - break; } return ret; diff --git a/src/chipset/opti895.c b/src/chipset/opti895.c index 77297ae95..f1878a51b 100644 --- a/src/chipset/opti895.c +++ b/src/chipset/opti895.c @@ -42,6 +42,9 @@ typedef struct opti895_t { smram_t *smram; } opti895_t; +static uint8_t masks[0x10] = { 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xe3, 0xff, 0xe3, 0xff, 0x00, 0xff, 0xff, 0xff }; + #ifdef ENABLE_OPTI895_LOG int opti895_do_log = ENABLE_OPTI895_LOG; @@ -153,8 +156,12 @@ opti895_write(uint16_t addr, uint8_t val, void *priv) } break; case 0x24: - if (((dev->idx >= 0x20) && (dev->idx <= 0x2f)) || ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { - dev->regs[dev->idx] = val; + if (((dev->idx >= 0x20) && (dev->idx <= 0x2f) && (dev->idx != 0x2c)) || + ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { + if (dev->idx > 0x2f) + dev->regs[dev->idx] = val; + else + dev->regs[dev->idx] = val & masks[dev->idx - 0x20]; opti895_log("dev->regs[%04x] = %08x\n", dev->idx, val); /* TODO: Registers 0x30-0x3F for OPTi 802GP and 898. */ @@ -217,7 +224,8 @@ opti895_read(uint16_t addr, void *priv) break; case 0x24: /* TODO: Registers 0x30-0x3F for OPTi 802GP and 898. */ - if (((dev->idx >= 0x20) && (dev->idx <= 0x2f)) || ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { + if (((dev->idx >= 0x20) && (dev->idx <= 0x2f) && (dev->idx != 0x2c)) || + ((dev->idx >= 0xe0) && (dev->idx <= 0xef))) { ret = dev->regs[dev->idx]; if (dev->idx == 0xe0) ret = (ret & 0xf6) | (in_smm ? 0x00 : 0x08) | !!dev->forced_green; diff --git a/src/cpu/x86_ops_pmode.h b/src/cpu/x86_ops_pmode.h index e84847a7b..4f32b0e37 100644 --- a/src/cpu/x86_ops_pmode.h +++ b/src/cpu/x86_ops_pmode.h @@ -430,12 +430,21 @@ op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) case 0x20: /*SMSW*/ if (cpu_mod != 3) SEG_CHECK_WRITE(cpu_state.ea_seg); - if (is486 || isibm486) - seteaw(msw); - else if (is386) - seteaw(msw | /* 0xFF00 */ 0xFFE0); - else - seteaw(msw | 0xFFF0); + if (is386 && is32 && (cpu_mod == 3)) { + if (is486 || isibm486) + seteaw(cr0); + else if (is386 && !cpu_16bitbus) + seteaw(cr0 | /* 0x7FFFFF00 */ 0x7FFFFFE0); + else + seteaw(cr0 | 0x7FFFFFF0); + } else { + if (is486 || isibm486) + seteaw(msw); + else if (is386 && !cpu_16bitbus) + seteaw(msw | /* 0xFF00 */ 0xFFE0); + else + seteaw(msw | 0xFFF0); + } CLOCK_CYCLES(2); PREFETCH_RUN(2, 2, rmdat, 0, 0, (cpu_mod == 3) ? 0 : 1, 0, ea32); break;