From 0b02fc37bc0bdb4ba409997a13759ab72199ad4b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 11 Mar 2018 18:26:44 +0100 Subject: [PATCH 01/23] Ported the most relevant PCem commits to 86Box. --- src/cpu/cpu.c | 14 +- src/cpu/cpu.h | 4 +- src/dma.c | 810 ++++++++++++++++++++---------------- src/dma.h | 45 +- src/machine/m_ps2_mca.c | 340 +++++++++++++++ src/machine/machine.h | 2 + src/machine/machine_table.c | 15 +- src/mca.h | 2 + src/mem.c | 45 +- src/mem.h | 2 + src/nvr_ps2.c | 4 + src/rom.c | 35 +- src/rom.h | 7 +- src/video/vid_svga.c | 11 +- src/video/vid_table.c | 164 ++++---- 15 files changed, 964 insertions(+), 536 deletions(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 6708f1766..80fe04641 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -8,7 +8,7 @@ * * CPU type handler. * - * Version: @(#)cpu.c 1.0.13 2018/03/02 + * Version: @(#)cpu.c 1.0.14 2018/03/11 * * Authors: Sarah Walker, * leilei, @@ -113,7 +113,7 @@ int cpuspeed; uint64_t cpu_CR4_mask; int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; -int cpu_prefetch_cycles, cpu_prefetch_width; +int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; int cpu_waitstates; int cpu_cache_int_enabled, cpu_cache_ext_enabled; int cpu_pci_speed; @@ -246,6 +246,8 @@ void cpu_set() isa_cycles = cpu_s->atclk_div; + cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000; + if (cpu_s->pci_speed) { pci_nonburst_time = 4*cpu_s->rspeed / cpu_s->pci_speed; @@ -2217,7 +2219,10 @@ void cpu_update_waitstates() { cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; - cpu_prefetch_width = cpu_16bitbus ? 2 : 4; + if (is486) + cpu_prefetch_width = 16; + else + cpu_prefetch_width = cpu_16bitbus ? 2 : 4; if (cpu_cache_int_enabled) { @@ -2251,4 +2256,7 @@ void cpu_update_waitstates() cpu_cycles_write = cpu_s->mem_write_cycles; cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_write_cycles; } + if (is486) + cpu_prefetch_cycles *= 4; + cpu_mem_prefetch_cycles = cpu_prefetch_cycles; } diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 38f18242c..f01b49438 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -8,7 +8,7 @@ * * CPU type handler. * - * Version: @(#)cpu.h 1.0.9 2018/03/02 + * Version: @(#)cpu.h 1.0.10 2018/03/11 * * Authors: Sarah Walker, * leilei, @@ -387,7 +387,7 @@ extern x86seg _oldds; #define ISA_CYCLES(x) ((x * isa_cycles) >> ISA_CYCLES_SHIFT) extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; -extern int cpu_prefetch_cycles, cpu_prefetch_width; +extern int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; extern int cpu_waitstates; extern int cpu_cache_int_enabled, cpu_cache_ext_enabled; extern int cpu_pci_speed; diff --git a/src/dma.c b/src/dma.c index e5ebd8bff..89fcb9c8a 100644 --- a/src/dma.c +++ b/src/dma.c @@ -8,7 +8,7 @@ * * Implementation of the Intel DMA controllers. * - * Version: @(#)dma.c 1.0.7 2017/12/15 + * Version: @(#)dma.c 1.0.8 2018/03/11 * * Authors: Sarah Walker, * Miran Grca, @@ -24,6 +24,7 @@ #include "cpu/cpu.h" #include "cpu/x86.h" #include "machine/machine.h" +#include "mca.h" #include "mem.h" #include "io.h" #include "dma.h" @@ -33,67 +34,74 @@ static uint8_t dmaregs[16]; static uint8_t dma16regs[16]; static uint8_t dmapages[16]; -DMA dma, dma16; +dma_t dma[8]; +static int dma_wp, dma16_wp; +static uint8_t dma_m; +static uint8_t dma_stat; +static uint8_t dma_stat_rq; +static uint8_t dma_command, dma16_command; + +static struct +{ + int xfr_command, xfr_channel; + int byte_ptr; + + int is_ps2; +} dma_ps2; + +#define DMA_PS2_IOA (1 << 0) +#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) +#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) +#define DMA_PS2_XFER_MASK (3 << 2) +#define DMA_PS2_DEC2 (1 << 4) +#define DMA_PS2_SIZE16 (1 << 6) + +static void dma_ps2_run(int channel); void dma_reset(void) { -#if 1 - int c; - dma.wp = 0; - for (c = 0; c < 16; c++) - dmaregs[c] = 0; - for (c = 0; c < 4; c++) - { - dma.mode[c] = 0; - dma.ac[c] = 0; - dma.cc[c] = 0; - dma.ab[c] = 0; - dma.cb[c] = 0; - } - dma.m = 0; - - dma16.wp = 0; - for (c = 0; c < 16; c++) - dma16regs[c] = 0; - for (c = 0; c < 4; c++) - { - dma16.mode[c] = 0; - dma16.ac[c] = 0; - dma16.cc[c] = 0; - dma16.ab[c] = 0; - dma16.cb[c] = 0; - } - dma16.m = 0; -#else - memset(dmaregs, 0, 16); - memset(dma16regs, 0, 16); - memset(dmapages, 0, 16); - memset(&dma, 0, sizeof(DMA)); - memset(&dma16, 0, sizeof(DMA)); -#endif + int c; + + dma_wp = dma16_wp = 0; + dma_m = 0; + + for (c = 0; c < 16; c++) + dmaregs[c] = 0; + for (c = 0; c < 8; c++) + { + dma[c].mode = 0; + dma[c].ac = 0; + dma[c].cc = 0; + dma[c].ab = 0; + dma[c].cb = 0; + dma[c].size = (c & 4) ? 1 : 0; + } } uint8_t dma_read(uint16_t addr, void *priv) { + int channel = (addr >> 1) & 3; uint8_t temp; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma.wp ^= 1; - if (dma.wp) - return dma.ac[(addr >> 1) & 3] & 0xff; - return (dma.ac[(addr >> 1) & 3] >> 8) & 0xff; + dma_wp ^= 1; + if (dma_wp) + return dma[channel].ac & 0xff; + return (dma[channel].ac >> 8) & 0xff; case 1: case 3: case 5: case 7: /*Count registers*/ - dma.wp ^= 1; - if (dma.wp) temp = dma.cc[(addr >> 1) & 3] & 0xff; - else temp = dma.cc[(addr >> 1) & 3] >> 8; + dma_wp ^= 1; + if (dma_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; return temp; case 8: /*Status register*/ - temp = dma.stat; - dma.stat = 0; + temp = dma_stat & 0xf; + dma_stat &= ~0xf; return temp; case 0xd: @@ -104,120 +112,129 @@ uint8_t dma_read(uint16_t addr, void *priv) void dma_write(uint16_t addr, uint8_t val, void *priv) { + int channel = (addr >> 1) & 3; dmaregs[addr & 0xf] = val; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma.wp ^= 1; - if (dma.wp) dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xffff00) | val; - else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00ff) | (val << 8); - dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3]; + dma_wp ^= 1; + if (dma_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ac = dma[channel].ab; return; case 1: case 3: case 5: case 7: /*Count registers*/ - dma.wp ^= 1; - if (dma.wp) dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0xff00) | val; - else dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); - dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3]; + dma_wp ^= 1; + if (dma_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; return; case 8: /*Control register*/ - dma.command = val; + dma_command = val; return; case 0xa: /*Mask*/ - if (val & 4) dma.m |= (1 << (val & 3)); - else dma.m &= ~(1 << (val & 3)); + if (val & 4) + dma_m |= (1 << (val & 3)); + else + dma_m &= ~(1 << (val & 3)); return; case 0xb: /*Mode*/ - dma.mode[val & 3] = val; - if (dma.is_ps2) + channel = (val & 3); + dma[channel].mode = val; + if (dma_ps2.is_ps2) { - dma.ps2_mode[val & 3] &= ~0x1c; + dma[channel].ps2_mode &= ~0x1c; if (val & 0x20) - dma.ps2_mode[val & 3] |= 0x10; + dma[channel].ps2_mode |= 0x10; if ((val & 0xc) == 8) - dma.ps2_mode[val & 3] |= 4; + dma[channel].ps2_mode |= 4; else if ((val & 0xc) == 4) - dma.ps2_mode[val & 3] |= 0xc; + dma[channel].ps2_mode |= 0xc; } return; case 0xc: /*Clear FF*/ - dma.wp = 0; + dma_wp = 0; return; case 0xd: /*Master clear*/ - dma.wp = 0; - dma.m = 0xf; + dma_wp = 0; + dma_m |= 0xf; return; case 0xf: /*Mask write*/ - dma.m = val & 0xf; + dma_m = (dma_m & 0xf0) | (val & 0xf); return; } } static uint8_t dma_ps2_read(uint16_t addr, void *priv) { + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; uint8_t temp = 0xff; switch (addr) { case 0x1a: - switch (dma.xfr_command) + switch (dma_ps2.xfr_command) { case 2: /*Address*/ case 3: - switch (dma.byte_ptr) + switch (dma_ps2.byte_ptr) { case 0: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] & 0xff) : (dma.ac[dma.xfr_channel] & 0xff); - dma.byte_ptr = 1; + temp = dma_c->ac & 0xff; + dma_ps2.byte_ptr = 1; break; case 1: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] >> 8) : (dma.ac[dma.xfr_channel] >> 8); - dma.byte_ptr = 2; + temp = (dma_c->ac >> 8) & 0xff; + dma_ps2.byte_ptr = 2; break; case 2: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] >> 16) : (dma.ac[dma.xfr_channel] >> 16); - dma.byte_ptr = 0; + temp = (dma_c->ac >> 16) & 0xff; + dma_ps2.byte_ptr = 0; break; } break; case 4: /*Count*/ case 5: - if (dma.byte_ptr) - temp = (dma.xfr_channel & 4) ? (dma16.cc[dma.xfr_channel & 3] >> 8) : (dma.cc[dma.xfr_channel] >> 8); + if (dma_ps2.byte_ptr) + temp = dma_c->cc >> 8; else - temp = (dma.xfr_channel & 4) ? (dma16.cc[dma.xfr_channel & 3] & 0xff) : (dma.cc[dma.xfr_channel] & 0xff); - dma.byte_ptr = (dma.byte_ptr + 1) & 1; + temp = dma_c->cc & 0xff; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; break; case 6: /*Read DMA status*/ - if (dma.byte_ptr) + if (dma_ps2.byte_ptr) { - temp = dma16.stat_rq | (dma16.stat << 4); - dma16.stat = 0; - dma16.stat_rq = 0; + temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); + dma_stat &= ~0xf0; + dma_stat_rq &= ~0xf0; } else { - temp = dma.stat_rq | (dma.stat << 4); - dma.stat = 0; - dma.stat_rq = 0; + temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); + dma_stat &= ~0xf; + dma_stat_rq &= ~0xf; } - dma.byte_ptr = (dma.byte_ptr + 1) & 1; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; break; case 7: /*Mode*/ - temp = (dma.xfr_channel & 4) ? dma16.ps2_mode[dma.xfr_channel & 3] : dma.ps2_mode[dma.xfr_channel]; + temp = dma_c->ps2_mode; break; case 8: /*Arbitration Level*/ - temp = (dma.xfr_channel & 4) ? dma16.arb_level[dma.xfr_channel & 3] : dma.arb_level[dma.xfr_channel]; + temp = dma_c->arb_level; break; default: - fatal("Bad XFR Read command %i channel %i\n", dma.xfr_command, dma.xfr_channel); + fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); } break; } @@ -227,119 +244,87 @@ static uint8_t dma_ps2_read(uint16_t addr, void *priv) static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) { + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; uint8_t mode; switch (addr) { case 0x18: - dma.xfr_channel = val & 0x7; - dma.xfr_command = val >> 4; - dma.byte_ptr = 0; - switch (dma.xfr_command) + dma_ps2.xfr_channel = val & 0x7; + dma_ps2.xfr_command = val >> 4; + dma_ps2.byte_ptr = 0; + switch (dma_ps2.xfr_command) { case 9: /*Set DMA mask*/ - if (dma.xfr_channel & 4) - dma16.m |= (1 << (dma.xfr_channel & 3)); - else - dma.m |= (1 << dma.xfr_channel); + dma_m |= (1 << dma_ps2.xfr_channel); break; case 0xa: /*Reset DMA mask*/ - if (dma.xfr_channel & 4) - dma16.m &= ~(1 << (dma.xfr_channel & 3)); - else - dma.m &= ~(1 << dma.xfr_channel); + dma_m &= ~(1 << dma_ps2.xfr_channel); + break; + case 0xb: + if (!(dma_m & (1 << dma_ps2.xfr_channel))) + dma_ps2_run(dma_ps2.xfr_channel); break; } break; case 0x1a: - switch (dma.xfr_command) + switch (dma_ps2.xfr_command) { + case 0: /*I/O address*/ + if (dma_ps2.byte_ptr) + dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); + else + dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + case 2: /*Address*/ - switch (dma.byte_ptr) + switch (dma_ps2.byte_ptr) { case 0: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0xffff00) | val; - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0xffff00) | val; - dma.byte_ptr = 1; + dma_c->ac = (dma_c->ac & 0xffff00) | val; + dma_ps2.byte_ptr = 1; break; case 1: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0xff00ff) | (val << 8); - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0xff00ff) | (val << 8); - dma.byte_ptr = 2; + dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); + dma_ps2.byte_ptr = 2; break; case 2: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0x00ffff) | (val << 16); - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0x00ffff) | (val << 16); - dma.byte_ptr = 0; + dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); + dma_ps2.byte_ptr = 0; break; } - if (dma.xfr_channel & 4) - dma16.ab[dma.xfr_channel & 3] = dma16.ac[dma.xfr_channel & 3]; - else - dma.ab[dma.xfr_channel] = dma.ac[dma.xfr_channel]; + dma_c->ab = dma_c->ac; break; case 4: /*Count*/ - if (dma.byte_ptr) - { - if (dma.xfr_channel & 4) - dma16.cc[dma.xfr_channel & 3] = (dma16.cc[dma.xfr_channel & 3] & 0xff) | (val << 8); - else - dma.cc[dma.xfr_channel] = (dma.cc[dma.xfr_channel] & 0xff) | (val << 8); - } + if (dma_ps2.byte_ptr) + dma_c->cc = (dma_c->cc & 0xff) | (val << 8); else - { - if (dma.xfr_channel & 4) - dma16.cc[dma.xfr_channel & 3] = (dma16.cc[dma.xfr_channel & 3] & 0xff00) | val; - else - dma.cc[dma.xfr_channel] = (dma.cc[dma.xfr_channel] & 0xff00) | val; - } - dma.byte_ptr = (dma.byte_ptr + 1) & 1; - if (dma.xfr_channel & 4) - dma16.cb[dma.xfr_channel & 3] = dma16.cc[dma.xfr_channel & 3]; - else - dma.cb[dma.xfr_channel] = dma.cc[dma.xfr_channel]; + dma_c->cc = (dma_c->cc & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + dma_c->cb = dma_c->cc; break; case 7: /*Mode register*/ mode = 0; - if (val & 0x10) + if (val & DMA_PS2_DEC2) mode |= 0x20; - if ((val & 0xc) == 4) + if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) mode |= 8; - else if ((val & 0xc) == 0xc) + else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) mode |= 4; - if ((val & 0x40) && !(dma.xfr_channel & 4)) - fatal("16-bit DMA on 8-bit channel\n"); - if (!(val & 0x40) && (dma.xfr_channel & 4)) - fatal("8-bit DMA on 16-bit channel\n"); - if (dma.xfr_channel & 4) - { - dma16.mode[dma.xfr_channel & 3] = (dma16.mode[dma.xfr_channel & 3] & ~0x2c) | mode; - dma16.ps2_mode[dma.xfr_channel & 3] = val; - } - else - { - dma.mode[dma.xfr_channel] = (dma.mode[dma.xfr_channel] & ~0x2c) | mode; - dma.ps2_mode[dma.xfr_channel] = val; - } + dma_c->mode = (dma_c->mode & ~0x2c) | mode; + dma_c->ps2_mode = val; + dma_c->size = val & DMA_PS2_SIZE16; break; case 8: /*Arbitration Level*/ - if (dma.xfr_channel & 4) - dma16.arb_level[dma.xfr_channel & 3] = val; - else - dma.arb_level[dma.xfr_channel] = val; + dma_c->arb_level = val; break; default: - fatal("Bad XFR command %i channel %i val %02x\n", dma.xfr_command, dma.xfr_channel, val); + fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); } break; } @@ -347,31 +332,34 @@ static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) uint8_t dma16_read(uint16_t addr, void *priv) { + int channel = ((addr >> 2) & 3) + 4; uint8_t temp; addr >>= 1; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma16.wp ^= 1; - if (dma.is_ps2) + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { - if (dma16.wp) - return dma16.ac[(addr >> 1) & 3] & 0xff; - return (dma16.ac[(addr >> 1) & 3] >> 8) & 0xff; + if (dma16_wp) + return dma[channel].ac; + return (dma[channel].ac >> 8) & 0xff; } - if (dma16.wp) - return (dma16.ac[(addr >> 1) & 3] >> 1) & 0xff; - return (dma16.ac[(addr >> 1) & 3] >> 9) & 0xff; + if (dma16_wp) + return (dma[channel].ac >> 1) & 0xff; + return (dma[channel].ac >> 9) & 0xff; case 1: case 3: case 5: case 7: /*Count registers*/ - dma16.wp ^= 1; - if (dma16.wp) temp = dma16.cc[(addr >> 1) & 3] & 0xff; - else temp = dma16.cc[(addr >> 1) & 3] >> 8; + dma16_wp ^= 1; + if (dma16_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; return temp; case 8: /*Status register*/ - temp = dma16.stat; - dma16.stat = 0; + temp = dma_stat >> 4; + dma_stat &= ~0xf0; return temp; } return dma16regs[addr & 0xf]; @@ -379,65 +367,75 @@ uint8_t dma16_read(uint16_t addr, void *priv) void dma16_write(uint16_t addr, uint8_t val, void *priv) { + int channel = ((addr >> 2) & 3) + 4; addr >>= 1; dma16regs[addr & 0xf] = val; switch (addr & 0xf) { case 0: case 2: case 4: case 6: /*Address registers*/ - dma16.wp ^= 1; - if (dma.is_ps2) + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { - if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xffff00) | val; - else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00ff) | (val << 8); + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); } else { - if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xfffe00) | (val << 1); - else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xfe01ff) | (val << 9); + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); + else + dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); } - dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3]; + dma[channel].ac = dma[channel].ab; return; case 1: case 3: case 5: case 7: /*Count registers*/ - dma16.wp ^= 1; - if (dma16.wp) dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0xff00) | val; - else dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); - dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3]; + dma16_wp ^= 1; + if (dma16_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; return; case 8: /*Control register*/ return; case 0xa: /*Mask*/ - if (val & 4) dma16.m |= (1 << (val & 3)); - else dma16.m &= ~(1 << (val & 3)); + if (val & 4) + dma_m |= (0x10 << (val & 3)); + else + dma_m &= ~(0x10 << (val & 3)); return; case 0xb: /*Mode*/ - dma16.mode[val & 3] = val; - if (dma.is_ps2) + channel = (val & 3) + 4; + dma[channel].mode = val; + if (dma_ps2.is_ps2) { - dma16.ps2_mode[val & 3] &= ~0x1c; + dma[channel].ps2_mode &= ~0x1c; if (val & 0x20) - dma16.ps2_mode[val & 3] |= 0x10; + dma[channel].ps2_mode |= 0x10; if ((val & 0xc) == 8) - dma16.ps2_mode[val & 3] |= 4; + dma[channel].ps2_mode |= 4; else if ((val & 0xc) == 4) - dma16.ps2_mode[val & 3] |= 0xc; + dma[channel].ps2_mode |= 0xc; } return; case 0xc: /*Clear FF*/ - dma16.wp = 0; + dma16_wp = 0; return; case 0xd: /*Master clear*/ - dma16.wp = 0; - dma16.m = 0xf; + dma16_wp = 0; + dma_m |= 0xf0; return; case 0xf: /*Mask write*/ - dma16.m = val&0xf; + dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); return; } } @@ -449,44 +447,44 @@ void dma_page_write(uint16_t addr, uint8_t val, void *priv) switch (addr & 0xf) { case 1: - dma.page[2] = (AT) ? val : val & 0xf; - dma.ab[2] = (dma.ab[2] & 0xffff) | (dma.page[2] << 16); - dma.ac[2] = (dma.ac[2] & 0xffff) | (dma.page[2] << 16); + dma[2].page = (AT) ? val : val & 0xf; + dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); + dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); break; case 2: - dma.page[3] = (AT) ? val : val & 0xf; - dma.ab[3] = (dma.ab[3] & 0xffff) | (dma.page[3] << 16); - dma.ac[3] = (dma.ac[3] & 0xffff) | (dma.page[3] << 16); + dma[3].page = (AT) ? val : val & 0xf; + dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); + dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); break; case 3: - dma.page[1] = (AT) ? val : val & 0xf; - dma.ab[1] = (dma.ab[1] & 0xffff) | (dma.page[1] << 16); - dma.ac[1] = (dma.ac[1] & 0xffff) | (dma.page[1] << 16); + dma[1].page = (AT) ? val : val & 0xf; + dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); + dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); break; case 7: - dma.page[0] = (AT) ? val : val & 0xf; - dma.ab[0] = (dma.ab[0] & 0xffff) | (dma.page[0] << 16); - dma.ac[0] = (dma.ac[0] & 0xffff) | (dma.page[0] << 16); + dma[0].page = (AT) ? val : val & 0xf; + dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); + dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); break; case 0x9: - dma16.page[2] = val & 0xfe; - dma16.ab[2] = (dma16.ab[2] & 0x1ffff) | (dma16.page[2] << 16); - dma16.ac[2] = (dma16.ac[2] & 0x1ffff) | (dma16.page[2] << 16); + dma[6].page = val & 0xfe; + dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); + dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); break; case 0xa: - dma16.page[3] = val & 0xfe; - dma16.ab[3] = (dma16.ab[3] & 0x1ffff) | (dma16.page[3] << 16); - dma16.ac[3] = (dma16.ac[3] & 0x1ffff) | (dma16.page[3] << 16); + dma[7].page = val & 0xfe; + dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); + dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); break; case 0xb: - dma16.page[1] = val & 0xfe; - dma16.ab[1] = (dma16.ab[1] & 0x1ffff) | (dma16.page[1] << 16); - dma16.ac[1] = (dma16.ac[1] & 0x1ffff) | (dma16.page[1] << 16); + dma[5].page = val & 0xfe; + dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); + dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); break; case 0xf: - dma16.page[0] = val & 0xfe; - dma16.ab[0] = (dma16.ab[0] & 0x1ffff) | (dma16.page[0] << 16); - dma16.ac[0] = (dma16.ac[0] & 0x1ffff) | (dma16.page[0] << 16); + dma[4].page = val & 0xfe; + dma[4].ab = (dma[4].ab & 0x1ffff) | (dma[4].page << 16); + dma[4].ac = (dma[4].ac & 0x1ffff) | (dma[4].page << 16); break; } } @@ -500,7 +498,7 @@ void dma_init(void) { io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL, NULL); io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); - dma.is_ps2 = 0; + dma_ps2.is_ps2 = 0; } void dma16_init(void) @@ -531,7 +529,7 @@ void ps2_dma_init(void) { io_sethandler(0x0018, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); io_sethandler(0x001a, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); - dma.is_ps2 = 1; + dma_ps2.is_ps2 = 1; } @@ -549,208 +547,280 @@ void _dma_write(uint32_t addr, uint8_t val) int dma_channel_read(int channel) { + dma_t *dma_c = &dma[channel]; uint16_t temp; int tc = 0; - if (dma.command & 0x04) - return DMA_NODATA; - - if (!AT) - refreshread(); - if (channel < 4) { - if (dma.m & (1 << channel)) - return DMA_NODATA; - if ((dma.mode[channel] & 0xC) != 8) - return DMA_NODATA; - - temp = _dma_read(dma.ac[channel]); - dma.stat_rq |= (1 << channel); - - if (dma.mode[channel] & 0x20) - { - if (dma.is_ps2) - dma.ac[channel]--; - else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] - 1) & 0xffff); - } - else - { - if (dma.is_ps2) - dma.ac[channel]++; - else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] + 1) & 0xffff); - } - dma.cc[channel]--; - if (dma.cc[channel] < 0) - { - tc = 1; - if (dma.mode[channel] & 0x10) /*Auto-init*/ - { - dma.cc[channel] = dma.cb[channel]; - dma.ac[channel] = dma.ab[channel]; - } - else - dma.m |= (1 << channel); - dma.stat |= (1 << channel); - } - - if (tc) - return temp | DMA_OVER; - return temp; + if (dma_command & 0x04) + return DMA_NODATA; } else { - channel &= 3; - if (dma16.m & (1 << channel)) - return DMA_NODATA; - if ((dma16.mode[channel] & 0xC) != 8) - return DMA_NODATA; + if (dma16_command & 0x04) + return DMA_NODATA; + } + + if (!AT) + refreshread(); - temp = _dma_read(dma16.ac[channel]) | - (_dma_read(dma16.ac[channel] + 1) << 8); - dma16.stat_rq |= (1 << channel); + if (dma_m & (1 << channel)) + return DMA_NODATA; + if ((dma_c->mode & 0xC) != 8) + return DMA_NODATA; + + if (!dma_c->size) + { + temp = _dma_read(dma_c->ac); - if (dma16.mode[channel] & 0x20) + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma16.ac[channel] -= 2; + if (dma_ps2.is_ps2) + dma_c->ac--; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); } else { - if (dma.is_ps2) - dma16.ac[channel] += 2; + if (dma_ps2.is_ps2) + dma_c->ac++; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] + 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } - - dma16.cc[channel]--; - if (dma16.cc[channel] < 0) - { - tc = 1; - if (dma16.mode[channel] & 0x10) /*Auto-init*/ - { - dma16.cc[channel] = dma16.cb[channel]; - dma16.ac[channel] = dma16.ab[channel]; - } - else - dma16.m |= (1 << channel); - dma16.stat |= (1 << channel); - } - - if (tc) - return temp | DMA_OVER; - return temp; } + else + { + temp = _dma_read(dma_c->ac) | + (_dma_read(dma_c->ac + 1) << 8); + + if (dma_c->mode & 0x20) + { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } + else + { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) + { + tc = 1; + if (dma_c->mode & 0x10) /*Auto-init*/ + { + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } + else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (tc) + return temp | DMA_OVER; + return temp; } int dma_channel_write(int channel, uint16_t val) { - if (dma.command & 0x04) - return DMA_NODATA; + dma_t *dma_c = &dma[channel]; + + if (channel < 4) + { + if (dma_command & 0x04) + return DMA_NODATA; + } + else + { + if (dma16_command & 0x04) + return DMA_NODATA; + } if (!AT) refreshread(); - if (channel < 4) + if (dma_m & (1 << channel)) + return DMA_NODATA; + if ((dma_c->mode & 0xC) != 4) + return DMA_NODATA; + + if (!dma_c->size) { - if (dma.m & (1 << channel)) - return DMA_NODATA; - if ((dma.mode[channel] & 0xC) != 4) - return DMA_NODATA; - - _dma_write(dma.ac[channel], val); - dma.stat_rq |= (1 << channel); - - if (dma.mode[channel] & 0x20) + _dma_write(dma_c->ac, val); + + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma.ac[channel]--; + if (dma_ps2.is_ps2) + dma_c->ac--; else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] - 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); } else { - if (dma.is_ps2) - dma.ac[channel]++; + if (dma_ps2.is_ps2) + dma_c->ac++; else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] + 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } - - dma.cc[channel]--; - if (dma.cc[channel] < 0) - { - if (dma.mode[channel] & 0x10) /*Auto-init*/ - { - dma.cc[channel] = dma.cb[channel]; - dma.ac[channel] = dma.ab[channel]; - } - else - dma.m |= (1 << channel); - dma.stat |= (1 << channel); - } - - if (dma.m & (1 << channel)) - return DMA_OVER; } else { - channel &= 3; - if (dma16.m & (1 << channel)) - return DMA_NODATA; - if ((dma16.mode[channel] & 0xC) != 4) - return DMA_NODATA; + _dma_write(dma_c->ac, val); + _dma_write(dma_c->ac + 1, val >> 8); - _dma_write(dma16.ac[channel], val); - _dma_write(dma16.ac[channel] + 1, val >> 8); - dma16.stat_rq |= (1 << channel); - - if (dma16.mode[channel] & 0x20) + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma16.ac[channel] -= 2; + if (dma_ps2.is_ps2) + dma_c->ac -= 2; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); } else { - if (dma.is_ps2) - dma16.ac[channel] += 2; + if (dma_ps2.is_ps2) + dma_c->ac += 2; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] + 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); } - - dma16.cc[channel]--; - if (dma16.cc[channel] < 0) - { - if (dma16.mode[channel] & 0x10) /*Auto-init*/ - { - dma16.cc[channel] = dma16.cb[channel]; - dma16.ac[channel] = dma16.ab[channel]; - } - else - dma16.m |= (1 << channel); - dma16.stat |= (1 << channel); - } - - if (dma16.m & (1 << channel)) - return DMA_OVER; } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) + { + if (dma_c->mode & 0x10) /*Auto-init*/ + { + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } + else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (dma_m & (1 << channel)) + return DMA_OVER; + return 0; } +static void dma_ps2_run(int channel) +{ + dma_t *dma_c = &dma[channel]; + + switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) + { + case DMA_PS2_XFER_MEM_TO_IO: + do + { + if (!dma_c->size) + { + uint8_t temp = _dma_read(dma_c->ac); + outb(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + outw(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + dma_stat |= (1 << channel); + break; + + case DMA_PS2_XFER_IO_TO_MEM: + do + { + if (!dma_c->size) + { + uint8_t temp = inb(dma_c->io_addr); + _dma_write(dma_c->ac, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + uint16_t temp = inw(dma_c->io_addr); + _dma_write(dma_c->ac, temp & 0xff); + _dma_write(dma_c->ac + 1, temp >> 8); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + ps2_cache_clean(); + dma_stat |= (1 << channel); + break; + + default: /*Memory verify*/ + do + { + if (!dma_c->size) + { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma->cc--; + } while (dma->cc > 0); + + dma_stat |= (1 << channel); + break; + } +} + int dma_mode(int channel) { if (channel < 4) { - return dma.mode[channel]; + return dma[channel].mode; } else { - return dma16.mode[channel & 3]; + return dma[channel & 3].mode; } } diff --git a/src/dma.h b/src/dma.h index f13102e83..223994a17 100644 --- a/src/dma.h +++ b/src/dma.h @@ -8,7 +8,7 @@ * * Implementation of the Intel DMA controllers. * - * Version: @(#)dma.h 1.0.4 2017/12/15 + * Version: @(#)dma.h 1.0.5 2018/03/11 * * Authors: Sarah Walker, * Miran Grca, @@ -25,32 +25,25 @@ #define DMA_VERIFY 0x20000 -typedef struct DMA { - uint32_t ab[4], - ac[4]; - uint16_t cb[4]; - int cc[4]; - int wp; - uint8_t m, - mode[4]; - uint8_t page[4]; - uint8_t stat, - stat_rq; - uint8_t command; - uint8_t request; - - int xfr_command, - xfr_channel; - int byte_ptr; - - int is_ps2; - uint8_t arb_level[4]; - uint8_t ps2_mode[4]; -} DMA; - - -extern DMA dma, dma16; +/*DMA*/ +typedef struct dma_t +{ + uint32_t ab, ac; + uint16_t cb; + int cc; + int wp; + uint8_t m, mode; + uint8_t page; + uint8_t stat, stat_rq; + uint8_t command; + int size; + + uint8_t ps2_mode; + uint8_t arb_level; + uint16_t io_addr; +} dma_t; +extern dma_t dma[8]; extern void dma_init(void); extern void dma16_init(void); diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 98c28180a..e9c74935a 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -41,6 +41,7 @@ static struct mem_mapping_t shadow_mapping; mem_mapping_t expansion_mapping; + mem_mapping_t cache_mapping; uint8_t (*planar_read)(uint16_t port); void (*planar_write)(uint16_t port, uint8_t val); @@ -51,8 +52,95 @@ static struct uint8_t mem_pos_regs[8]; uint8_t mem_2mb_pos_regs[8]; + + int pending_cache_miss; } ps2; +/*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any + proper cache emulation, it's faked a bit here. + + Port E2 is used for cache diagnostics. Bit 7 seems to be set on a cache miss, + toggling bit 2 seems to clear this. The BIOS performs at least the following + tests : + + - Disable RAM, access low 64kb (386) / 8kb (486), execute code from cache to + access low memory and verify that there are no cache misses. + - Write to low memory using DMA, read low memory and verify that all accesses + cause cache misses. + - Read low memory, verify that first access is cache miss. Read again and + verify that second access is cache hit. + + These tests are also performed on the 486 model 70, despite there being no + external cache on this system. Port E2 seems to control the internal cache on + these systems. Presumably this port is connected to KEN#/FLUSH# on the 486. + This behaviour is required to pass the timer interrupt test on the 486 version + - the BIOS uses a fixed length loop that will terminate too early on a 486/25 + if it executes from internal cache. + + To handle this, 86Box uses some basic heuristics : + - If cache is enabled but RAM is disabled, accesses to low memory go directly + to cache memory. + - Reads to cache addresses not 'valid' will set the cache miss flag, and mark + that line as valid. + - Cache flushes will clear the valid array. + - DMA via the undocumented PS/2 command 0xb will clear the valid array. + - Disabling the cache will clear the valid array. + - Disabling the cache will also mark shadowed ROM areas as using ROM timings. + This works around the timing loop mentioned above. +*/ + +static uint8_t ps2_cache[65536]; +static int ps2_cache_valid[65536/8]; + +static uint8_t ps2_read_cache_ram(uint32_t addr, void *priv) +{ +// pclog("ps2_read_cache_ram: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc); + if (!ps2_cache_valid[addr >> 3]) + { + ps2_cache_valid[addr >> 3] = 1; + ps2.mem_regs[2] |= 0x80; + } + else + ps2.pending_cache_miss = 0; + + return ps2_cache[addr]; +} +static uint16_t ps2_read_cache_ramw(uint32_t addr, void *priv) +{ +// pclog("ps2_read_cache_ramw: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc); + if (!ps2_cache_valid[addr >> 3]) + { + ps2_cache_valid[addr >> 3] = 1; + ps2.mem_regs[2] |= 0x80; + } + else + ps2.pending_cache_miss = 0; + + return *(uint16_t *)&ps2_cache[addr]; +} +static uint32_t ps2_read_cache_raml(uint32_t addr, void *priv) +{ +// pclog("ps2_read_cache_raml: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc); + if (!ps2_cache_valid[addr >> 3]) + { + ps2_cache_valid[addr >> 3] = 1; + ps2.mem_regs[2] |= 0x80; + } + else + ps2.pending_cache_miss = 0; + + return *(uint32_t *)&ps2_cache[addr]; +} +static void ps2_write_cache_ram(uint32_t addr, uint8_t val, void *priv) +{ +// pclog("ps2_write_cache_ram: addr=%08x val=%02x %04x:%04x %i\n", addr, val, CS,cpu_state.pc, ins); + ps2_cache[addr] = val; +} + +void ps2_cache_clean(void) +{ + memset(ps2_cache_valid, 0, sizeof(ps2_cache_valid)); +} static uint8_t ps2_read_shadow_ram(uint32_t addr, void *priv) { @@ -139,6 +227,30 @@ static uint8_t model_55sx_read(uint16_t port) return 0xff; } +static uint8_t model_70_type3_read(uint16_t port) +{ + switch (port) + { + case 0x100: + return 0xff; + case 0x101: + return 0xf9; + case 0x102: + return ps2.option[0]; + case 0x103: + return ps2.option[1]; + case 0x104: + return ps2.option[2]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; + } + return 0xff; +} + static uint8_t model_80_read(uint16_t port) { switch (port) @@ -296,6 +408,56 @@ static void model_55sx_write(uint16_t port, uint8_t val) } } +static void model_70_type3_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x100: + break; + case 0x101: + break; + case 0x102: + lpt1_remove(); + serial_remove(1); + if (val & 0x04) + { + if (val & 0x08) + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + else + serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + } + else + serial_remove(1); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps2.option[0] = val; + break; + case 0x105: + ps2.option[3] = val; + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + } +} + + static void model_80_write(uint16_t port, uint8_t val) { switch (port) @@ -737,6 +899,169 @@ static void mem_encoding_write(uint16_t addr, uint8_t val, void *p) mem_encoding_update(); } +static uint8_t mem_encoding_read_cached(uint16_t addr, void *p) +{ + switch (addr) + { + case 0xe0: + return ps2.mem_regs[0]; + case 0xe1: + return ps2.mem_regs[1]; + case 0xe2: + return ps2.mem_regs[2]; + } + return 0xff; +} + +static void mem_encoding_write_cached(uint16_t addr, uint8_t val, void *p) +{ + uint8_t old; + + switch (addr) + { + case 0xe0: + ps2.mem_regs[0] = val; + break; + case 0xe1: + ps2.mem_regs[1] = val; + break; + case 0xe2: + old = ps2.mem_regs[2]; + ps2.mem_regs[2] = (ps2.mem_regs[2] & 0x80) | (val & ~0x88); + if (val & 2) + { +// pclog("Clear latch - %i\n", ps2.pending_cache_miss); + if (ps2.pending_cache_miss) + ps2.mem_regs[2] |= 0x80; + else + ps2.mem_regs[2] &= ~0x80; + ps2.pending_cache_miss = 0; + } + + if ((val & 0x21) == 0x20 && (old & 0x21) != 0x20) + ps2.pending_cache_miss = 1; + if ((val & 0x21) == 0x01 && (old & 0x21) != 0x01) + ps2_cache_clean(); + if (val & 0x01) + ram_mid_mapping.flags |= MEM_MAPPING_ROM; + else + ram_mid_mapping.flags &= ~MEM_MAPPING_ROM; + break; + } +// pclog("mem_encoding_write: addr=%02x val=%02x %04x:%04x %02x %02x\n", addr, val, CS,cpu_state.pc, ps2.mem_regs[1],ps2.mem_regs[2]); + mem_encoding_update(); + if ((ps2.mem_regs[1] & 0x10) && (ps2.mem_regs[2] & 0x21) == 0x20) + { + mem_mapping_disable(&ram_low_mapping); + mem_mapping_enable(&ps2.cache_mapping); + flushmmucache(); + } + else + { + mem_mapping_disable(&ps2.cache_mapping); + mem_mapping_enable(&ram_low_mapping); + flushmmucache(); + } +} + +static void ps2_mca_board_model_70_type34_init(int is_type4) +{ + ps2_mca_board_common_init(); + + mem_remap_top_256k(); + ps2.split_addr = mem_size * 1024; + mca_init(4); + + ps2.planar_read = model_70_type3_read; + ps2.planar_write = model_70_type3_write; + + device_add(&ps2_nvr_device); + + io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached, NULL, NULL, NULL); + + ps2.mem_regs[1] = 2; + + switch (mem_size/1024) + { + case 2: + ps2.option[1] = 0xa6; + ps2.option[2] = 0x01; + break; + case 4: + ps2.option[1] = 0xaa; + ps2.option[2] = 0x01; + break; + case 6: + ps2.option[1] = 0xca; + ps2.option[2] = 0x01; + break; + case 8: + default: + ps2.option[1] = 0xca; + ps2.option[2] = 0x02; + break; + } + + if (is_type4) + ps2.option[2] |= 0x04; /*486 CPU*/ + + mem_mapping_add(&ps2.cache_mapping, + 0, + is_type4 ? (8 * 1024) : (64 * 1024), + ps2_read_cache_ram, + ps2_read_cache_ramw, + ps2_read_cache_raml, + ps2_write_cache_ram, + NULL, + NULL, + ps2_cache, + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.cache_mapping); + + if (mem_size > 8192) + { + /* Only 8 MB supported on planar, create a memory expansion card for the rest */ + mem_mapping_set_addr(&ram_high_mapping, 0x100000, 0x700000); + + ps2.mem_pos_regs[0] = 0xff; + ps2.mem_pos_regs[1] = 0xfc; + + switch (mem_size/1024) + { + case 10: + ps2.mem_pos_regs[4] = 0xfe; + break; + case 12: + ps2.mem_pos_regs[4] = 0xfa; + break; + case 14: + ps2.mem_pos_regs[4] = 0xea; + break; + case 16: + ps2.mem_pos_regs[4] = 0xaa; + break; + } + + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL); + mem_mapping_add(&ps2.expansion_mapping, + 0x800000, + (mem_size - 8192)*1024, + mem_read_ram, + mem_read_ramw, + mem_read_raml, + mem_write_ram, + mem_write_ramw, + mem_write_raml, + &ram[0x800000], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.expansion_mapping); + } + + device_add(&ps1vga_device); +} + static void ps2_mca_board_model_80_type2_init(int is486) { ps2_mca_board_common_init(); @@ -876,6 +1201,21 @@ machine_ps2_model_55sx_init(machine_t *model) ps2_mca_board_model_55sx_init(); } +void +machine_ps2_model_70_type3_init(machine_t *model) +{ + machine_ps2_common_init(model); + + ps2_mca_board_model_70_type34_init(0); +} + +void +machine_ps2_model_70_type4_init(machine_t *model) +{ + machine_ps2_common_init(model); + + ps2_mca_board_model_70_type34_init(1); +} void machine_ps2_model_80_init(machine_t *model) diff --git a/src/machine/machine.h b/src/machine/machine.h index d7fcbcce8..2cd9880f4 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -162,6 +162,8 @@ extern void machine_ps1_m2133_init(machine_t *); extern void machine_ps2_m30_286_init(machine_t *); extern void machine_ps2_model_50_init(machine_t *); extern void machine_ps2_model_55sx_init(machine_t *); +extern void machine_ps2_model_70_type3_init(machine_t *); +extern void machine_ps2_model_70_type4_init(machine_t *); extern void machine_ps2_model_80_init(machine_t *); #ifdef WALTJE extern void machine_ps2_model_80_486_init(machine_t *); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index bdbcea0d8..aa53e86d6 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.24 2018/03/06 + * Version: @(#)machine_table.c 1.0.24 2018/03/11 * * Authors: Sarah Walker, * Miran Grca, @@ -47,11 +47,11 @@ machine_t machines[] = { { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 0, machine_europc_init, NULL, NULL }, { "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device, NULL }, { "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device, NULL }, - { "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 0, machine_xt_t1000_init, t1000_get_device, NULL }, + { "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 0, machine_xt_t1000_init, NULL, NULL }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL }, #endif - { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device, nvr_at_close }, + { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL, nvr_at_close }, { "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close }, { "[8086] Amstrad PC1640", ROM_PC1640, "pc1640", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL, nvr_at_close }, @@ -60,7 +60,7 @@ machine_t machines[] = { { "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close }, { "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL, NULL }, { "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL, NULL }, - { "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 0, machine_xt_t1200_init, t1200_get_device, NULL }, + { "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 0, machine_xt_t1200_init, NULL, NULL }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) { "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL }, #endif @@ -104,6 +104,7 @@ machine_t machines[] = { #if defined(DEV_BRANCH) && defined(USE_PORTABLE3) { "[386DX ISA] Compaq Portable III (386)", ROM_PORTABLEIII386, "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_compaq_init, NULL, nvr_at_close }, #endif + { "[386DX MCA] IBM PS/2 model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL, nvr_at_close }, { "[386DX MCA] IBM PS/2 model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 12, 1, 63, machine_ps2_model_80_init, NULL, nvr_at_close }, @@ -113,6 +114,8 @@ machine_t machines[] = { { "[486 ISA] DTK PKM-0038S E-2", ROM_DTK486, "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_dtk486_init, NULL, nvr_at_close }, { "[486 ISA] IBM PS/1 model 2133", ROM_IBMPS1_2133, "ibmps1_2133", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 1, 64, 1, 127, machine_ps1_m2133_init, NULL, nvr_at_close }, + { "[486 MCA] IBM PS/2 model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 64, 2, 63, machine_ps2_model_70_type4_init, NULL, nvr_at_close }, + #ifdef WALTJE { "[486 MCA] IBM PS/2 model 80-486", ROM_IBMPS2_M80_486, "ibmps2_m80-486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 32, 1, 63, machine_ps2_model_80_486_init, NULL, nvr_at_close }, #endif @@ -135,9 +138,7 @@ machine_t machines[] = { { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL, nvr_at_close }, { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, -#endif { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL, nvr_at_close }, { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL, nvr_at_close }, @@ -158,9 +159,7 @@ machine_t machines[] = { { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL, nvr_at_close }, { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, -#endif { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL, nvr_at_close }, { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL, nvr_at_close }, diff --git a/src/mca.h b/src/mca.h index 26e29e7c5..dd88c1f98 100644 --- a/src/mca.h +++ b/src/mca.h @@ -3,3 +3,5 @@ extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int add extern void mca_set_index(int index); extern uint8_t mca_read(uint16_t port); extern void mca_write(uint16_t port, uint8_t val); + +extern void ps2_cache_clean(void); \ No newline at end of file diff --git a/src/mem.c b/src/mem.c index 291a47deb..93ae0ec47 100644 --- a/src/mem.c +++ b/src/mem.c @@ -389,15 +389,14 @@ uint8_t *getpccache(uint32_t a) } a&=rammask; - if (isram[a>>16]) - { - if ((a >> 16) != 0xF || shadowbios) - addreadlookup(a2, a); - return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; - } - if (_mem_exec[a >> 14]) { + if (_mem_mapping_r[a >> 14]->flags & MEM_MAPPING_ROM) + cpu_prefetch_cycles = cpu_rom_prefetch_cycles; + else + cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + + return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xFFF)]; } @@ -1282,24 +1281,24 @@ void mem_add_bios() { if (AT || (romset == ROM_XI8088 && xi8088_bios_128kb())) { - mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL, 0); - mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_EXTERNAL, 0); - mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL, 0); - mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); } - mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL, 0); - mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_EXTERNAL, 0); - mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL, 0); - mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[0], (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, 0, 0); - mem_mapping_add(&bios_high_mapping[1], (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), 0, 0); - mem_mapping_add(&bios_high_mapping[2], (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), 0, 0); - mem_mapping_add(&bios_high_mapping[3], (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), 0, 0); - mem_mapping_add(&bios_high_mapping[4], (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), 0, 0); - mem_mapping_add(&bios_high_mapping[5], (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), 0, 0); - mem_mapping_add(&bios_high_mapping[6], (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), 0, 0); - mem_mapping_add(&bios_high_mapping[7], (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[0], (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[1], (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[2], (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[3], (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[4], (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[5], (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[6], (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[7], (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), MEM_MAPPING_ROM, 0); } int mem_a20_key = 0, mem_a20_alt = 0; diff --git a/src/mem.h b/src/mem.h index 2366a2ab6..9a5583d36 100644 --- a/src/mem.h +++ b/src/mem.h @@ -68,6 +68,8 @@ typedef struct mem_mapping_t #define MEM_MAPPING_EXTERNAL 1 /*Only present on internal bus (RAM)*/ #define MEM_MAPPING_INTERNAL 2 +/*Executing from ROM may involve additional wait states*/ +#define MEM_MAPPING_ROM 4 extern uint8_t *ram,*rom; extern uint8_t romext[32768]; diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index a9a0ab979..2fcd89d72 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -67,6 +67,8 @@ static void *ps2_nvr_init(device_t *info) switch (romset) { + case ROM_IBMPS2_M70_TYPE3: f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"rb"); break; + case ROM_IBMPS2_M70_TYPE4: f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"rb"); break; case ROM_IBMPS2_M80: f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"rb"); break; #ifdef WALTJE case ROM_IBMPS2_M80_486: f = nvr_fopen(L"ibmps2_m80-486_sec.nvr", L"rb"); break; @@ -90,6 +92,8 @@ void ps2_nvr_close(void *p) switch (romset) { + case ROM_IBMPS2_M70_TYPE3: f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"wb"); break; + case ROM_IBMPS2_M70_TYPE4: f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"wb"); break; case ROM_IBMPS2_M80: f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"wb"); break; #ifdef WALTJE case ROM_IBMPS2_M80_486: f = nvr_fopen(L"ibmps2_m80-486_sec.nvr", L"wb"); break; diff --git a/src/rom.c b/src/rom.c index 20295155f..c36600291 100644 --- a/src/rom.c +++ b/src/rom.c @@ -13,7 +13,7 @@ * - c386sx16 BIOS fails checksum * - the loadfont() calls should be done elsewhere * - * Version: @(#)rom.c 1.0.35 2018/03/06 + * Version: @(#)rom.c 1.0.34 2018/03/11 * * Authors: Sarah Walker, * Miran Grca, @@ -256,7 +256,7 @@ rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint addr, sz, rom_read, rom_readw, rom_readl, mem_write_null, mem_write_nullw, mem_write_nulll, - rom->rom, flags, rom); + rom->rom, flags | MEM_MAPPING_ROM, rom); return(0); } @@ -283,7 +283,7 @@ rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int addr, sz, rom_read, rom_readw, rom_readl, mem_write_null, mem_write_nullw, mem_write_nulll, - rom->rom, flags, rom); + rom->rom, flags | MEM_MAPPING_ROM, rom); return(0); } @@ -674,14 +674,11 @@ rom_load_bios(int rom_id) break; case ROM_SPC4216P: - if (rom_load_linear( - L"roms/machines/spc4216p/phoenix.bin", - 0x000000, 65536, 0, rom)) return(1); - if (rom_load_interleaved( + if (! rom_load_interleaved( L"roms/machines/spc4216p/7101.u8", L"roms/machines/spc4216p/ac64.u10", - 0x000000, 65536, 0, rom)) return(1); - break; + 0x000000, 65536, 0, rom)) break; + return(1); case ROM_KMXC02: if (rom_load_linear( @@ -720,6 +717,22 @@ rom_load_bios(int rom_id) biosmask = 0x1ffff; return(1); + case ROM_IBMPS2_M70_TYPE3: + if (! rom_load_interleaved( + L"roms/machines/ibmps2_m70_type3/70-a_even.bin", + L"roms/machines/ibmps2_m70_type3/70-a_odd.bin", + 0x000000, 65536, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_IBMPS2_M70_TYPE4: + if (! rom_load_interleaved( + L"roms/machines/ibmps2_m70_type4/70-b_even.bin", + L"roms/machines/ibmps2_m70_type4/70-b_odd.bin", + 0x000000, 65536, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + case ROM_DTK486: if (rom_load_linear( L"roms/machines/dtk486/4siw005.bin", @@ -848,14 +861,12 @@ rom_load_bios(int rom_id) biosmask = 0x1ffff; return(1); -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) case ROM_MRTHOR: if (! rom_load_linear( L"roms/machines/mrthor/mr_atx.bio", 0x000000, 131072, 0, rom)) break; biosmask = 0x1ffff; return(1); -#endif case ROM_ZAPPA: if (! rom_load_linear( @@ -911,7 +922,6 @@ rom_load_bios(int rom_id) if (!rom_load_linear( L"roms/machines/t1000/t1000.rom", 0x000000, 32768, 0, rom)) break; - memcpy(rom + 0x8000, rom, 0x8000); biosmask = 0x7fff; return(1); @@ -920,7 +930,6 @@ rom_load_bios(int rom_id) if (!rom_load_linear( L"roms/machines/t1200/t1200_019e.ic15.bin", 0x000000, 32768, 0, rom)) break; - memcpy(rom + 0x8000, rom, 0x8000); biosmask = 0x7fff; return(1); diff --git a/src/rom.h b/src/rom.h index 477a4788f..ce6e3b2c1 100644 --- a/src/rom.h +++ b/src/rom.h @@ -8,7 +8,7 @@ * * Definitions for the ROM image handler. * - * Version: @(#)rom.h 1.0.17 2018/03/06 + * Version: @(#)rom.h 1.0.16 2018/03/02 * * Author: Fred N. van Kempen, * Copyright 2018 Fred N. van Kempen. @@ -127,6 +127,9 @@ enum { #endif ROM_IBMPS1_2133, + ROM_IBMPS2_M70_TYPE3, + ROM_IBMPS2_M70_TYPE4, + #ifdef WALTJE ROM_IBMPS2_M80_486, #endif @@ -147,9 +150,7 @@ enum { ROM_PRESIDENT, /* President Award 430FX PCI/430FX/Award/Unknown SIO */ ROM_THOR, /* Intel Advanced_ATX/430FX/AMI/NS PC87306 */ -#if defined(DEV_BRANCH) && defined(USE_MRTHOR) ROM_MRTHOR, /* Intel Advanced_ATX/430FX/MR.BIOS/NS PC87306 */ -#endif ROM_ACERM3A, /* Acer M3A/430HX/Acer/SMC FDC37C932FR */ ROM_ACERV35N, /* Acer V35N/430HX/Acer/SMC FDC37C932FR */ diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 6bd9ea9d4..695644c5e 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,7 +11,7 @@ * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * - * Version: @(#)vid_svga.c 1.0.24 2018/03/05 + * Version: @(#)vid_svga.c 1.0.24 2018/03/11 * * Authors: Sarah Walker, * Miran Grca, @@ -109,14 +109,9 @@ void svga_out(uint16_t addr, uint8_t val, void *p) case 0x3C2: svga->miscout = val; svga->vidclock = val & 4; - if (val & 1) - { - io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); - } - else - { + io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + if (!(val & 1)) io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); - } svga_recalctimings(svga); break; case 0x3C4: diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 49594dcf5..cde1ebd0f 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -8,7 +8,7 @@ * * Define all known video cards. * - * Version: @(#)vid_table.c 1.0.24 2018/03/03 + * Version: @(#)vid_table.c 1.0.23 2018/03/11 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -85,93 +85,91 @@ typedef struct { static VIDEO_CARD video_cards[] = { - {"None", "none", NULL, GFX_NONE }, - {"Internal", "internal", NULL, GFX_INTERNAL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device, GFX_MACH64GX_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - {"[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device, GFX_ATIKOREANVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - {"[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device, GFX_VGA88, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device, GFX_VGACHARGER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - {"[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device, GFX_VGAEDGE16, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, -#if defined(DEV_BRANCH) && defined(USE_XL24) - {"[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device, GFX_VGAWONDERXL24, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, -#endif - {"[ISA] CGA", "cga", &cga_device, GFX_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Chips & Technologies SuperEGA", "superega", &sega_device, GFX_SUPER_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device, GFX_CL_GD5428_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - {"[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device, GFX_CL_GD5429_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - {"[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device, GFX_CL_GD5434_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - {"[ISA] Compaq ATI VGA Wonder XL (ATI-28800-5)", "compaq_ati28800", &compaq_ati28800_device, GFX_VGAWONDERXL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - {"[ISA] Compaq CGA", "compaq_cga", &compaq_cga_device, GFX_COMPAQ_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device, GFX_COMPAQ_CGA_2, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Compaq EGA", "compaq_ega", &cpqega_device, GFX_COMPAQ_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] EGA", "ega", &ega_device, GFX_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Hercules", "hercules", &hercules_device, GFX_HERCULES, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Hercules Plus", "hercules_plus", &herculesplus_device, GFX_HERCULESPLUS, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] MDA", "mda", &mda_device, GFX_MDA, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] MDSI Genius", "genius", &genius_device, GFX_GENIUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] OAK OTI-037C", "oti037c", &oti037c_device, GFX_OTI037C, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, - {"[ISA] OAK OTI-067", "oti067", &oti067_device, GFX_OTI067, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, - {"[ISA] OAK OTI-077", "oti077", &oti077_device, GFX_OTI077, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, - {"[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device, GFX_PVGA1A, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device, GFX_WD90C11, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device, GFX_WD90C30, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, - {"[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "None", "none", NULL, GFX_NONE }, + { "Internal", "internal", NULL, GFX_INTERNAL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device, GFX_MACH64GX_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device, GFX_ATIKOREANVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + { "[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device, GFX_VGA88, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device, GFX_VGACHARGER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + { "[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device, GFX_VGAEDGE16, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device,GFX_VGAWONDERXL24, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + { "[ISA] CGA", "cga", &cga_device, GFX_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device, GFX_SUPER_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device, GFX_CL_GD5428_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, + { "[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device, GFX_CL_GD5429_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, + { "[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device, GFX_CL_GD5434_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, + { "[ISA] Compaq ATI VGA Wonder XL (ATI-28800-5)","compaq_ati28800", &compaq_ati28800_device, GFX_VGAWONDERXL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + { "[ISA] Compaq CGA", "compaq_cga", &compaq_cga_device, GFX_COMPAQ_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device, GFX_COMPAQ_CGA_2, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] Compaq EGA", "compaq_ega", &cpqega_device, GFX_COMPAQ_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] EGA", "ega", &ega_device, GFX_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] Hercules", "hercules", &hercules_device, GFX_HERCULES, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] Hercules Plus", "hercules_plus", &herculesplus_device, GFX_HERCULESPLUS, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] MDA", "mda", &mda_device, GFX_MDA, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + { "[ISA] MDSI Genius", "genius", &genius_device, GFX_GENIUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"[ISA] OAK OTI-037C", "oti037c", &oti037c_device, GFX_OTI037C, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, + {"[ISA] OAK OTI-067", "oti067", &oti067_device, GFX_OTI067, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, + {"[ISA] OAK OTI-077", "oti077", &oti077_device, GFX_OTI077, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, + {"[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device, GFX_PVGA1A, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device, GFX_WD90C11, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device, GFX_WD90C30, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, + {"[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, #if defined(DEV_BRANCH) && defined(USE_TI) - {"[ISA] TI CF62011 SVGA", "ti_cf62011", &ti_cf62011_device, GFX_TICF62011, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"[ISA] TI CF62011 SVGA", "ti_cf62011", &ti_cf62011_device, GFX_TICF62011, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, #endif - {"[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - {"[ISA] Tseng ET4000AX", "et4000ax", &et4000_device, GFX_ET4000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, - {"[ISA] VGA", "vga", &vga_device, GFX_VGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[ISA] Wyse 700", "wy700", &wy700_device, GFX_WY700, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - {"[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device, GFX_MACH64GX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, - {"[PCI] ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, - {"[PCI] Cardex Tseng ET4000/w32p", "et4000w32p_pci", &et4000w32p_cardex_pci_device, GFX_ET4000W32_CARDEX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, - {"[PCI] Cirrus Logic CL-GD 5430", "cl_gd5430_pci", &gd5430_pci_device, GFX_CL_GD5430_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[PCI] Cirrus Logic CL-GD 5434", "cl_gd5434_pci", &gd5434_pci_device, GFX_CL_GD5434_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[PCI] Cirrus Logic CL-GD 5436", "cl_gd5436_pci", &gd5436_pci_device, GFX_CL_GD5436_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, + {"[ISA] Tseng ET4000AX", "et4000ax", &et4000_device, GFX_ET4000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"[ISA] VGA", "vga", &vga_device, GFX_VGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"[ISA] Wyse 700", "wy700", &wy700_device, GFX_WY700, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device, GFX_MACH64GX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"[PCI] ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"[PCI] Cardex Tseng ET4000/w32p", "et4000w32p_pci", &et4000w32p_cardex_pci_device,GFX_ET4000W32_CARDEX_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, + {"[PCI] Cirrus Logic CL-GD 5430", "cl_gd5430_pci", &gd5430_pci_device, GFX_CL_GD5430_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[PCI] Cirrus Logic CL-GD 5434", "cl_gd5434_pci", &gd5434_pci_device, GFX_CL_GD5434_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[PCI] Cirrus Logic CL-GD 5436", "cl_gd5436_pci", &gd5436_pci_device, GFX_CL_GD5436_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, #if defined(DEV_BRANCH) && defined(USE_STEALTH32) - {"[PCI] Diamond Stealth 32 (Tseng ET4000/w32p)","stealth32_pci", &et4000w32p_pci_device, GFX_ET4000W32_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, + {"[PCI] Diamond Stealth 32 (Tseng ET4000/w32p)","stealth32_pci", &et4000w32p_pci_device, GFX_ET4000W32_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, #endif - {"[PCI] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_pci",&s3_virge_pci_device, GFX_VIRGE_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[PCI] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_pci",&s3_virge_988_pci_device, GFX_VIRGEVX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, - {"[PCI] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_pci", &s3_diamond_stealth64_pci_device, GFX_STEALTH64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, + {"[PCI] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_pci",&s3_virge_pci_device, GFX_VIRGE_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, + {"[PCI] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_pci",&s3_virge_988_pci_device, GFX_VIRGEVX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, + {"[PCI] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_pci", &s3_diamond_stealth64_pci_device,GFX_STEALTH64_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, #if defined(DEV_BRANCH) && defined(USE_RIVA) - {"[PCI] nVidia RIVA 128", "riva128", &riva128_device, GFX_RIVA128, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}}, - {"[PCI] nVidia RIVA TNT", "rivatnt", &rivatnt_device, GFX_RIVATNT, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}}, - {"[PCI] nVidia RIVA TNT2", "rivatnt2", &rivatnt2_device, GFX_RIVATNT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}}, + {"[PCI] nVidia RIVA 128", "riva128", &riva128_device, GFX_RIVA128, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}}, + {"[PCI] nVidia RIVA TNT", "rivatnt", &rivatnt_device, GFX_RIVATNT, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}}, + {"[PCI] nVidia RIVA TNT2", "rivatnt2", &rivatnt2_device, GFX_RIVATNT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}}, #endif - {"[PCI] Number Nine 9FX (S3 Trio64)", "n9_9fx_pci", &s3_9fx_pci_device, GFX_N9_9FX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[PCI] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_pci", &s3_bahamas64_pci_device, GFX_BAHAMAS64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, - {"[PCI] Phoenix S3 Vision864", "px_vision864_pci", &s3_phoenix_vision864_pci_device, GFX_PHOENIX_VISION864_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, - {"[PCI] Phoenix S3 Trio32", "px_trio32_pci", &s3_phoenix_trio32_pci_device, GFX_PHOENIX_TRIO32_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[PCI] Phoenix S3 Trio64", "px_trio64_pci", &s3_phoenix_trio64_pci_device, GFX_PHOENIX_TRIO64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[PCI] S3 ViRGE/DX", "virge375_pci", &s3_virge_375_pci_device, GFX_VIRGEDX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[PCI] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_pci",&s3_virge_375_4_pci_device, GFX_VIRGEDX4_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[PCI] Trident TGUI9440", "tgui9440_pci", &tgui9440_pci_device, GFX_TGUI9440_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, - {"[VLB] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_vlb", &mach64gx_vlb_device, GFX_MACH64GX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, - {"[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device, GFX_ET4000W32_CARDEX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, - {"[VLB] Cirrus Logic CL-GD 5429", "cl_gd5429_vlb", &gd5429_vlb_device, GFX_CL_GD5429_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[VLB] Cirrus Logic CL-GD 5434", "cl_gd5434_vlb", &gd5434_vlb_device, GFX_CL_GD5434_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[PCI] Number Nine 9FX (S3 Trio64)", "n9_9fx_pci", &s3_9fx_pci_device, GFX_N9_9FX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"[PCI] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_pci", &s3_bahamas64_pci_device, GFX_BAHAMAS64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, + {"[PCI] Phoenix S3 Vision864", "px_vision864_pci", &s3_phoenix_vision864_pci_device,GFX_PHOENIX_VISION864_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, + {"[PCI] Phoenix S3 Trio32", "px_trio32_pci", &s3_phoenix_trio32_pci_device,GFX_PHOENIX_TRIO32_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"[PCI] Phoenix S3 Trio64", "px_trio64_pci", &s3_phoenix_trio64_pci_device,GFX_PHOENIX_TRIO64_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"[PCI] S3 ViRGE/DX", "virge375_pci", &s3_virge_375_pci_device, GFX_VIRGEDX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, + {"[PCI] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_pci",&s3_virge_375_4_pci_device,GFX_VIRGEDX4_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, + {"[PCI] Trident TGUI9440", "tgui9440_pci", &tgui9440_pci_device, GFX_TGUI9440_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, + {"[VLB] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_vlb", &mach64gx_vlb_device, GFX_MACH64GX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device,GFX_ET4000W32_CARDEX_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, + {"[VLB] Cirrus Logic CL-GD 5428", "cl_gd5428_vlb", &gd5428_vlb_device, GFX_CL_GD5428_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[VLB] Cirrus Logic CL-GD 5429", "cl_gd5429_vlb", &gd5429_vlb_device, GFX_CL_GD5429_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[VLB] Cirrus Logic CL-GD 5434", "cl_gd5434_vlb", &gd5434_vlb_device, GFX_CL_GD5434_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, #if defined(DEV_BRANCH) && defined(USE_STEALTH32) - {"[VLB] Diamond Stealth 32 (Tseng ET4000/w32p)","stealth32_vlb", &et4000w32p_vlb_device, GFX_ET4000W32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, + {"[VLB] Diamond Stealth 32 (Tseng ET4000/w32p)","stealth32_vlb", &et4000w32p_vlb_device, GFX_ET4000W32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, #endif - {"[VLB] Diamond SpeedStar PRO (CL-GD5428)", "cl_gd5428_vlb", &gd5428_vlb_device, GFX_CL_GD5428_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[VLB] Diamond SpeedStar PRO SE (CL-GD5430)", "cl_gd5430_vlb", &gd5430_vlb_device, GFX_CL_GD5430_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[VLB] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_vlb",&s3_virge_vlb_device, GFX_VIRGE_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[VLB] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_vlb",&s3_virge_988_vlb_device, GFX_VIRGEVX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, - {"[VLB] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_vlb", &s3_diamond_stealth64_vlb_device, GFX_STEALTH64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, - {"[VLB] Number Nine 9FX (S3 Trio64)", "n9_9fx_vlb", &s3_9fx_vlb_device, GFX_N9_9FX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[VLB] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_vlb", &s3_bahamas64_vlb_device, GFX_BAHAMAS64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, - {"[VLB] Phoenix S3 Vision864", "px_vision864_vlb", &s3_phoenix_vision864_vlb_device, GFX_PHOENIX_VISION864_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, - {"[VLB] Phoenix S3 Trio32", "px_trio32_vlb", &s3_phoenix_trio32_vlb_device, GFX_PHOENIX_TRIO32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[VLB] Phoenix S3 Trio64", "px_trio64_vlb", &s3_phoenix_trio64_vlb_device, GFX_PHOENIX_TRIO64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, - {"[VLB] S3 ViRGE/DX", "virge375_vlb", &s3_virge_375_vlb_device, GFX_VIRGEDX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[VLB] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_vlb",&s3_virge_375_4_vlb_device, GFX_VIRGEDX4_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, - {"[VLB] Trident TGUI9400CXi", "tgui9400cxi_vlb", &tgui9400cxi_device, GFX_TGUI9400CXI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, - {"[VLB] Trident TGUI9440", "tgui9440_vlb", &tgui9440_vlb_device, GFX_TGUI9440_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, - {"", "", NULL, -1 } + {"[VLB] Diamond SpeedStar PRO SE (CL-GD5430)", "cl_gd5430_vlb", &gd5430_vlb_device, GFX_CL_GD5430_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[VLB] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_vlb",&s3_virge_vlb_device, GFX_VIRGE_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, + {"[VLB] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_vlb",&s3_virge_988_vlb_device, GFX_VIRGEVX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, + {"[VLB] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_vlb", &s3_diamond_stealth64_vlb_device,GFX_STEALTH64_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, + {"[VLB] Number Nine 9FX (S3 Trio64)", "n9_9fx_vlb", &s3_9fx_vlb_device, GFX_N9_9FX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"[VLB] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_vlb", &s3_bahamas64_vlb_device, GFX_BAHAMAS64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, + {"[VLB] Phoenix S3 Vision864", "px_vision864_vlb", &s3_phoenix_vision864_vlb_device,GFX_PHOENIX_VISION864_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, + {"[VLB] Phoenix S3 Trio32", "px_trio32_vlb", &s3_phoenix_trio32_vlb_device,GFX_PHOENIX_TRIO32_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"[VLB] Phoenix S3 Trio64", "px_trio64_vlb", &s3_phoenix_trio64_vlb_device,GFX_PHOENIX_TRIO64_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"[VLB] S3 ViRGE/DX", "virge375_vlb", &s3_virge_375_vlb_device, GFX_VIRGEDX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, + {"[VLB] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_vlb",&s3_virge_375_4_vlb_device,GFX_VIRGEDX4_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, + {"[VLB] Trident TGUI9400CXi", "tgui9400cxi_vlb", &tgui9400cxi_device, GFX_TGUI9400CXI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, + {"[VLB] Trident TGUI9440", "tgui9440_vlb", &tgui9440_vlb_device, GFX_TGUI9440_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, + {"", "", NULL, -1 } }; @@ -317,6 +315,8 @@ int video_is_mda(void) case ROM_IBMPS2_M30_286: case ROM_IBMPS2_M50: case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: case ROM_IBMPS2_M80: case ROM_IBMPS1_2121: case ROM_T3100E: @@ -348,6 +348,8 @@ int video_is_cga(void) case ROM_IBMPS2_M30_286: case ROM_IBMPS2_M50: case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: case ROM_IBMPS2_M80: case ROM_IBMPS1_2121: return 0; @@ -378,6 +380,8 @@ int video_is_ega_vga(void) case ROM_IBMPS2_M30_286: case ROM_IBMPS2_M50: case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: case ROM_IBMPS2_M80: case ROM_IBMPS1_2121: return 1; From 5a8c30ba76fa06cd7f964db7d2a6fdf61f9bf420 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Sun, 11 Mar 2018 18:31:47 +0100 Subject: [PATCH 02/23] Fixed a compile breaking mistake --- src/video/vid_table.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/video/vid_table.c b/src/video/vid_table.c index cde1ebd0f..56800e09d 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -93,7 +93,9 @@ video_cards[] = { { "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device, GFX_VGACHARGER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, { "[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device, GFX_VGAEDGE16, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, { "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, +#if defined(DEV_BRANCH) && defined(USE_XL24) { "[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device,GFX_VGAWONDERXL24, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, +#endif { "[ISA] CGA", "cga", &cga_device, GFX_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, { "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device, GFX_SUPER_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device, GFX_CL_GD5428_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, From 113e3079bfdec6c3ceee0626416cfef759b7fbe2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 12 Mar 2018 00:32:33 +0100 Subject: [PATCH 03/23] The AMI non-PS/2 keyboard controller no longer uses bit 5 for keyboard mode, fixes CMOS Setup on the AMI WinBIOS 486. --- src/keyboard_at.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keyboard_at.c b/src/keyboard_at.c index f2fe83b7f..15b7a5062 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -8,7 +8,7 @@ * * Intel 8042 (AT keyboard controller) emulation. * - * Version: @(#)keyboard_at.c 1.0.27 2018/03/02 + * Version: @(#)keyboard_at.c 1.0.28 2018/03/12 * * Authors: Sarah Walker, * Miran Grca, @@ -960,7 +960,7 @@ kbd_cmd_write(atkbd_t *kbd, uint8_t val) /* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT); PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. */ - if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + if (((kbd->flags & KBC_VEN_MASK) == KBC_VEN_AMI) || ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) { keyboard_mode &= ~CCB_PCMODE; mouse_scan = !(val & 0x20); From 1e25dc24e34bb4a1baedeb8d7de361ba7190e0a5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 12 Mar 2018 02:27:49 +0100 Subject: [PATCH 04/23] Updated ROM set link in README.md. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66aa93238..b0c10351c 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ guide: 7. In order to test your fresh build, replace the `86Box.exe` in your current 86Box enviroment with your freshly built one. If you do not have a pre-existing 86Box environment, download the latest successful build from - http://ci.86box.net, and the ROM set from http://tinyurl.com/rs20180302. + http://ci.86box.net, and the ROM set from http://tinyurl.com/rs20180312. 8. Enjoy using and testing the emulator! :) If you encounter issues at any step or have additional questions, please join From 67f6649a2689c0ecb282433a9e7348035707c4ac Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 12 Mar 2018 15:19:36 +0100 Subject: [PATCH 05/23] Applied the ATI Korean VGA patch from greatpsycho. --- src/video/vid_ati28800.c | 83 ++++++++++++--- src/video/vid_svga.c | 11 +- src/video/vid_svga_render.c | 205 +++++++++++++++++++++--------------- src/video/vid_svga_render.h | 9 +- 4 files changed, 198 insertions(+), 110 deletions(-) diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index cc6be6487..5a9c7093f 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -8,7 +8,7 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * Version: @(#)vid_ati28800.c 1.0.9 2018/03/05 + * Version: @(#)vid_ati28800.c 1.0.10 2018/03/12 * * Authors: Sarah Walker, * Miran Grca, @@ -59,7 +59,7 @@ typedef struct ati28800_t uint8_t regs[256]; int index; - uint32_t memory; + uint32_t memory; } ati28800_t; @@ -69,7 +69,7 @@ int in_get_korean_font_kind_set; int get_korean_font_enabled; int get_korean_font_index; uint16_t get_korean_font_base; -extern int dbcs_mode_enabled; +int ksc5601_mode_enabled; static void ati28800_out(uint16_t addr, uint8_t val, void *p) @@ -106,9 +106,14 @@ static void ati28800_out(uint16_t addr, uint8_t val, void *p) case 0xb3: ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1); break; - case 0xb6: - if((old ^ val) & 0x10) svga_recalctimings(svga); - break; + case 0xb6: + if((old ^ val) & 0x10) svga_recalctimings(svga); + break; + case 0xb8: + if((old ^ val) & 0x40) svga_recalctimings(svga); + break; + case 0xb9: + if((old ^ val) & 2) svga_recalctimings(svga); } break; @@ -149,7 +154,7 @@ void ati28800k_out(uint16_t addr, uint8_t val, void *p) case 0x1CF: if(ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20)) { - dbcs_mode_enabled = val & 0x20; + ksc5601_mode_enabled = val & 0x20; svga_recalctimings(svga); } @@ -291,13 +296,44 @@ static void ati28800_recalctimings(svga_t *svga) { ati28800_t *ati28800 = (ati28800_t *)svga->p; - if (ati28800->regs[0xb6] & 0x10) - { + switch(((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1) | ((svga->miscout & 0x0C) >> 2)) + { + case 0x00: svga->clock = cpuclock / 42954000.0; break; + case 0x01: svga->clock = cpuclock / 48771000.0; break; + case 0x03: svga->clock = cpuclock / 36000000.0; break; + case 0x04: svga->clock = cpuclock / 50350000.0; break; + case 0x05: svga->clock = cpuclock / 56640000.0; break; + case 0x07: svga->clock = cpuclock / 44900000.0; break; + case 0x08: svga->clock = cpuclock / 30240000.0; break; + case 0x09: svga->clock = cpuclock / 32000000.0; break; + case 0x0A: svga->clock = cpuclock / 37500000.0; break; + case 0x0B: svga->clock = cpuclock / 39000000.0; break; + case 0x0C: svga->clock = cpuclock / 40000000.0; break; + case 0x0D: svga->clock = cpuclock / 56644000.0; break; + case 0x0E: svga->clock = cpuclock / 75000000.0; break; + case 0x0F: svga->clock = cpuclock / 65000000.0; break; + default: break; + } + + if(ati28800->regs[0xb8] & 0x40) svga->clock *= 2; + + + if (ati28800->regs[0xb6] & 0x10) + { svga->hdisp <<= 1; svga->htotal <<= 1; svga->rowoffset <<= 1; - } + } + if(svga->crtc[0x17] & 4) + { + svga->vtotal <<= 1; + svga->dispend <<= 1; + svga->vsyncstart <<= 1; + svga->split <<= 1; + svga->vblankstart <<= 1; + } + if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ { svga->render = svga_render_8bpp_highres; @@ -307,6 +343,16 @@ static void ati28800_recalctimings(svga_t *svga) } } +void ati28800k_recalctimings(svga_t *svga) +{ + ati28800_recalctimings(svga); + + if (svga->render == svga_render_text_80 && ksc5601_mode_enabled) + { + svga->render = svga_render_text_80_ksc5601; + } +} + void * ati28800k_init(device_t *info) { @@ -321,13 +367,13 @@ ati28800k_init(device_t *info) get_korean_font_enabled = 0; get_korean_font_kind = 0; in_get_korean_font_kind_set = 0; - dbcs_mode_enabled = 0; + ksc5601_mode_enabled = 0; rom_init(&ati28800->bios_rom, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); loadfont(FONT_ATIKOR_PATH, 6); svga_init(&ati28800->svga, ati28800, ati28800->memory << 10, /*Memory size, default 512KB*/ - ati28800_recalctimings, + ati28800k_recalctimings, ati28800k_in, ati28800k_out, NULL, NULL); @@ -457,6 +503,17 @@ ati28800_force_redraw(void *priv) ati->svga.fullchange = changeframecount; } +void ati28800k_add_status_info(char *s, int max_len, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + char temps[128]; + + svga_add_status_info(s, max_len, &ati28800->svga); + + sprintf(temps, "Korean SVGA mode enabled : %s\n\n", ksc5601_mode_enabled ? "Yes" : "No"); + strncat(s, temps, max_len); +} + static void ati28800_add_status_info(char *s, int max_len, void *priv) { ati28800_t *ati = (ati28800_t *)priv; @@ -537,7 +594,7 @@ device_t ati28800k_device = ati28800k_available, ati28800_speed_changed, ati28800_force_redraw, - ati28800_add_status_info, + ati28800k_add_status_info, ati28800_config }; diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 695644c5e..92b17be32 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,7 +11,7 @@ * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * - * Version: @(#)vid_svga.c 1.0.24 2018/03/11 + * Version: @(#)vid_svga.c 1.0.25 2018/03/12 * * Authors: Sarah Walker, * Miran Grca, @@ -385,15 +385,6 @@ void svga_recalctimings(svga_t *svga) if (svga->crtc[9] & 0x20) svga->vblankstart |= 0x200; svga->vblankstart++; - if(svga->crtc[0x17] & 4) - { - svga->vtotal <<= 1; - svga->dispend <<= 1; - svga->vsyncstart <<= 1; - svga->split <<= 1; - svga->vblankstart <<= 1; - } - svga->hdisp = svga->crtc[1]; svga->hdisp++; diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 5f24264d0..818e25d57 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -8,7 +8,7 @@ * * SVGA renderers. * - * Version: @(#)vid_svga_render.c 1.0.7 2018/03/05 + * Version: @(#)vid_svga_render.c 1.0.8 2018/03/12 * * Authors: Sarah Walker, * Miran Grca, @@ -92,9 +92,6 @@ uint32_t shade[5][256] = } }; -int dbcs_mode_enabled = 0; - - void svga_render_blank(svga_t *svga) { int x, xx; @@ -208,7 +205,7 @@ void svga_render_text_80(svga_t *svga) uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; int x, xx; int drawcursor; - uint8_t chr, attr, dat, nextchr; + uint8_t chr, attr, dat; uint32_t charaddr; int fg, bg; int xinc = (svga->seqregs[1] & 1) ? 8 : 9; @@ -220,83 +217,6 @@ void svga_render_text_80(svga_t *svga) attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; - if(dbcs_mode_enabled && x + xinc < svga->hdisp && chr & 0x80) - { - nextchr = svga->vram[((svga->ma + 4) << 1) & svga->vram_display_mask]; - if(nextchr & 0x80) - { - if (drawcursor) - { - bg = svga->pallook[svga->egapal[attr & 15]]; - fg = svga->pallook[svga->egapal[attr >> 4]]; - } - else - { - fg = svga->pallook[svga->egapal[attr & 15]]; - bg = svga->pallook[svga->egapal[attr >> 4]]; - if (attr & 0x80 && svga->attrregs[0x10] & 8) - { - bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; - if (svga->blink & 16) - fg = bg; - } - } - - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc]; - if (svga->seqregs[1] & 1) - { - for (xx = 0; xx < 8; xx++) - p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - p[xx] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) - p[8] = bg; - else - p[8] = (dat & 1) ? fg : bg; - } - - attr = svga->vram[(((svga->ma + 4) << 1) + 1) & svga->vram_display_mask]; - if (drawcursor) - { - bg = svga->pallook[svga->egapal[attr & 15]]; - fg = svga->pallook[svga->egapal[attr >> 4]]; - } - else - { - fg = svga->pallook[svga->egapal[attr & 15]]; - bg = svga->pallook[svga->egapal[attr >> 4]]; - if (attr & 0x80 && svga->attrregs[0x10] & 8) - { - bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; - if (svga->blink & 16) - fg = bg; - } - } - - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc + 16]; - if (svga->seqregs[1] & 1) - { - for (xx = 0; xx < 8; xx++) - p[xx+8] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - p[xx+9] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) - p[17] = bg; - else - p[17] = (dat & 1) ? fg : bg; - } - svga->ma += 8; - p += xinc * 2; - continue; - } - } - if (attr & 8) charaddr = svga->charsetb + (chr * 128); else charaddr = svga->charseta + (chr * 128); @@ -342,6 +262,127 @@ void svga_render_text_80(svga_t *svga) } } +void svga_render_text_80_ksc5601(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) + { + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + int x, xx; + int drawcursor; + uint8_t chr, attr, dat, nextchr; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 8 : 9; + + for (x = 0; x < svga->hdisp; x += xinc) + { + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask]; + nextchr = svga->vram[((svga->ma + 4) << 1) & svga->vram_display_mask]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + + if (drawcursor) + { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; + } + else + { + fg = svga->pallook[svga->egapal[attr & 15]]; + bg = svga->pallook[svga->egapal[attr >> 4]]; + if (attr & 0x80 && svga->attrregs[0x10] & 8) + { + bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; + if (svga->blink & 16) + fg = bg; + } + } + + fg = svga_color_transform(fg); + bg = svga_color_transform(bg); + + if(x + xinc < svga->hdisp && (chr & nextchr & 0x80)) + { + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc]; + } + else + { + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + dat = svga->vram[charaddr + (svga->sc << 2)]; + } + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[8] = bg; + else + p[8] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + + if(x + xinc < svga->hdisp && (chr & nextchr & 0x80)) + { + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + if (drawcursor) + { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; + } + else + { + fg = svga->pallook[svga->egapal[attr & 15]]; + bg = svga->pallook[svga->egapal[attr >> 4]]; + if (attr & 0x80 && svga->attrregs[0x10] & 8) + { + bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; + if (svga->blink & 16) + fg = bg; + } + } + + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc + 16]; + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[8] = bg; + else + p[8] = (dat & 1) ? fg : bg; + } + + svga->ma += 4; + p += xinc; + x += xinc; + } + } + svga->ma &= svga->vram_display_mask; + } +} + void svga_render_2bpp_lowres(svga_t *svga) { int changed_offset; diff --git a/src/video/vid_svga_render.h b/src/video/vid_svga_render.h index cfad3585d..4bbc43272 100644 --- a/src/video/vid_svga_render.h +++ b/src/video/vid_svga_render.h @@ -8,12 +8,12 @@ * * SVGA renderers. * - * Version: @(#)vid_svga_render.h 1.0.0 2017/05/30 + * Version: @(#)vid_svga_render.h 1.0.1 2018/03/12 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ extern int firstline_draw, lastline_draw; @@ -29,9 +29,8 @@ extern uint8_t edatlookup[4][4]; void svga_render_blank(svga_t *svga); void svga_render_text_40(svga_t *svga); -void svga_render_text_40_12(svga_t *svga); void svga_render_text_80(svga_t *svga); -void svga_render_text_80_12(svga_t *svga); +void svga_render_text_80_ksc5601(svga_t *svga); void svga_render_2bpp_lowres(svga_t *svga); void svga_render_2bpp_highres(svga_t *svga); From 622212759e27deb6c49f4e92f382263b5e49918a Mon Sep 17 00:00:00 2001 From: TC1995 Date: Mon, 12 Mar 2018 22:03:10 +0100 Subject: [PATCH 06/23] Ported wait state change from PCem. --- src/cpu/cpu.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 80fe04641..626b48f02 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -246,7 +246,10 @@ void cpu_set() isa_cycles = cpu_s->atclk_div; - cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000; + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; + else + cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000; if (cpu_s->pci_speed) { @@ -2259,4 +2262,6 @@ void cpu_update_waitstates() if (is486) cpu_prefetch_cycles *= 4; cpu_mem_prefetch_cycles = cpu_prefetch_cycles; + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; } From 9957190f2fd3f31867868f55443d25439ba676f1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 13 Mar 2018 01:39:33 +0100 Subject: [PATCH 07/23] Removed the empty macro definition of READ1BPP that was not used anywhere. --- src/video/vid_ati_mach64.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index fe349f185..d8478bfdf 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -8,7 +8,7 @@ * * ATi Mach64 graphics card emulation. * - * Version: @(#)vid_ati_mach64.c 1.0.14 2018/03/10 + * Version: @(#)vid_ati_mach64.c 1.0.15 2018/03/13 * * Authors: Sarah Walker, * Miran Grca, @@ -1150,8 +1150,6 @@ void mach64_start_line(mach64_t *mach64) else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; \ else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; -#define READ1BPP(addr, dat, width) - #define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ { \ case 0x0: dest_dat = ~dest_dat; break; \ From 4ca7abf6fe36c7e20e556bdddda562c16177dcd6 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 13 Mar 2018 02:48:24 +0100 Subject: [PATCH 08/23] Ported over the PCem AT keyboard fix. --- src/keyboard_at.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/keyboard_at.c b/src/keyboard_at.c index 15b7a5062..0db081f43 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -8,7 +8,7 @@ * * Intel 8042 (AT keyboard controller) emulation. * - * Version: @(#)keyboard_at.c 1.0.28 2018/03/12 + * Version: @(#)keyboard_at.c 1.0.29 2018/03/13 * * Authors: Sarah Walker, * Miran Grca, @@ -91,7 +91,7 @@ typedef struct { uint8_t status; uint8_t mem[0x100]; uint8_t out; - int out_new; + int out_new, out_delayed; uint8_t secr_phase; uint8_t mem_addr; @@ -645,7 +645,7 @@ kbd_poll(void *priv) kbdlog("ATkbd: want keyboard data\n"); if (kbd->mem[0] & 0x01) picint(2); - kbd->out = kbd->out_new; + keyboard_at.out = keyboard_at.out_new & 0xff; kbd->out_new = -1; kbd->status |= STAT_OFULL; kbd->status &= ~STAT_IFULL; @@ -656,8 +656,16 @@ kbd_poll(void *priv) if (kbd->out_new == -1 && !(kbd->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { - kbd->out_new = key_ctrl_queue[key_ctrl_queue_start]; + keyboard_at.out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && + keyboard_at.out_delayed != -1) { + keyboard_at.out_new = keyboard_at.out_delayed; + keyboard_at.out_delayed = -1; + } else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && + !(keyboard_at.mem[0] & 0x10) && keyboard_at.out_delayed != -1) { + keyboard_at.out_new = keyboard_at.out_delayed; + keyboard_at.out_delayed = -1; } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1/* && !(kbd->mem[0] & 0x20)*/ && (mouse_queue_start != mouse_queue_end)) { kbd->out_new = mouse_queue[mouse_queue_start] | 0x100; @@ -675,6 +683,11 @@ kbd_adddata(uint8_t val) { key_ctrl_queue[key_ctrl_queue_end] = val; key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; + + if (!(keyboard_at.out_new & 0x300)) { + keyboard_at.out_delayed = keyboard_at.out_new; + keyboard_at.out_new = -1; + } } From ddcb901421cf4e93b5fa6ed1d19545b38ccbeb10 Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 13 Mar 2018 03:46:10 +0100 Subject: [PATCH 09/23] Ported over the VARCem NVR commit. --- src/86box.h | 3 +- src/keyboard_at.c | 28 +- src/machine/m_at_t3100e.c | 262 +++--- src/machine/m_at_t3100e.h | 65 +- src/machine/m_at_t3100e_vid.c | 763 +++++++++++++++ src/machine/m_europc.c | 561 +++++------ src/machine/m_europc_hdc.c | 53 +- src/machine/m_xt_t1000.c | 1653 +++++++++++++++++++-------------- src/machine/m_xt_t1000.h | 62 +- src/machine/m_xt_t1000_vid.c | 753 +++++++++++++++ src/machine/machine_table.c | 8 +- src/nvr.c | 721 +++----------- src/nvr.h | 218 ++--- src/nvr_at.c | 785 +++++++++++++--- src/nvr_ps2.c | 224 +++-- src/nvr_ps2.h | 45 +- src/nvr_tc8521.c | 115 --- src/nvr_tc8521.h | 12 - src/pc.c | 7 +- src/rtc_tc8521.c | 221 ----- src/rtc_tc8521.h | 33 - src/win/Makefile.mingw | 11 +- 22 files changed, 4206 insertions(+), 2397 deletions(-) create mode 100644 src/machine/m_at_t3100e_vid.c create mode 100644 src/machine/m_xt_t1000_vid.c delete mode 100644 src/nvr_tc8521.c delete mode 100644 src/nvr_tc8521.h delete mode 100644 src/rtc_tc8521.c delete mode 100644 src/rtc_tc8521.h diff --git a/src/86box.h b/src/86box.h index 2a7f52999..c1cb9369c 100644 --- a/src/86box.h +++ b/src/86box.h @@ -8,7 +8,7 @@ * * Main include file for the application. * - * Version: @(#)86box.h 1.0.17 2018/01/18 + * Version: @(#)86box.h 1.0.18 2018/03/13 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -105,6 +105,7 @@ extern int cpu_manufacturer, /* (C) cpu manufacturer */ cpu, /* (C) cpu type */ cpu_use_dynarec, /* (C) cpu uses/needs Dyna */ enable_external_fpu; /* (C) enable external FPU */ +extern int enable_sync; /* (C) enable time sync */ #ifdef ENABLE_LOG_TOGGLES diff --git a/src/keyboard_at.c b/src/keyboard_at.c index 0db081f43..ea7357c28 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -8,7 +8,7 @@ * * Intel 8042 (AT keyboard controller) emulation. * - * Version: @(#)keyboard_at.c 1.0.29 2018/03/13 + * Version: @(#)keyboard_at.c 1.0.30 2018/03/13 * * Authors: Sarah Walker, * Miran Grca, @@ -645,7 +645,7 @@ kbd_poll(void *priv) kbdlog("ATkbd: want keyboard data\n"); if (kbd->mem[0] & 0x01) picint(2); - keyboard_at.out = keyboard_at.out_new & 0xff; + kbd->out = kbd->out_new & 0xff; kbd->out_new = -1; kbd->status |= STAT_OFULL; kbd->status &= ~STAT_IFULL; @@ -656,16 +656,16 @@ kbd_poll(void *priv) if (kbd->out_new == -1 && !(kbd->status & STAT_OFULL) && key_ctrl_queue_start != key_ctrl_queue_end) { - keyboard_at.out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; + kbd->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; - else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && - keyboard_at.out_delayed != -1) { - keyboard_at.out_new = keyboard_at.out_delayed; - keyboard_at.out_delayed = -1; - } else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && - !(keyboard_at.mem[0] & 0x10) && keyboard_at.out_delayed != -1) { - keyboard_at.out_new = keyboard_at.out_delayed; - keyboard_at.out_delayed = -1; + } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1 && + kbd->out_delayed != -1) { + kbd->out_new = kbd->out_delayed; + kbd->out_delayed = -1; + } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1 && + !(kbd->mem[0] & 0x10) && kbd->out_delayed != -1) { + kbd->out_new = kbd->out_delayed; + kbd->out_delayed = -1; } else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1/* && !(kbd->mem[0] & 0x20)*/ && (mouse_queue_start != mouse_queue_end)) { kbd->out_new = mouse_queue[mouse_queue_start] | 0x100; @@ -684,9 +684,9 @@ kbd_adddata(uint8_t val) key_ctrl_queue[key_ctrl_queue_end] = val; key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; - if (!(keyboard_at.out_new & 0x300)) { - keyboard_at.out_delayed = keyboard_at.out_new; - keyboard_at.out_new = -1; + if (!(CurrentKbd->out_new & 0x300)) { + CurrentKbd->out_delayed = CurrentKbd->out_new; + CurrentKbd->out_new = -1; } } diff --git a/src/machine/m_at_t3100e.c b/src/machine/m_at_t3100e.c index 3b9e2933e..9031d430d 100644 --- a/src/machine/m_at_t3100e.c +++ b/src/machine/m_at_t3100e.c @@ -1,9 +1,155 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Toshiba T3100e. + * + * The Toshiba 3100e is a 286-based portable. + * + * To bring up the BIOS setup screen hold down the 'Fn' key + * on booting. + * + * Memory management + * ~~~~~~~~~~~~~~~~~ + * + * Motherboard memory is divided into: + * - Conventional memory: Either 512k or 640k + * - Upper memory: Either 512k or 384k, depending on + * amount of conventional memory. + * Upper memory can be used as EMS or XMS. + * - High memory: 0-4Mb, depending on RAM installed. + * The BIOS setup screen allows some or + * all of this to be used as EMS; the + * remainder is XMS. + * + * Additional memory (either EMS or XMS) can also be provided + * by ISA expansion cards. + * + * Under test in PCem, the BIOS will boot with up to 65368Kb + * of memory in total (16Mb less 16k). However it will give + * an error with RAM sizes above 8Mb, if any of the high + * memory is allocated as EMS, because the builtin EMS page + * registers can only access up to 8Mb. + * + * Memory is controlled by writes to I/O port 8084h: + * Bit 7: Always 0 } + * Bit 6: Always 1 } These bits select which motherboard + * Bit 5: Always 0 } function to access. + * Bit 4: Set to treat upper RAM as XMS + * Bit 3: Enable external RAM boards? + * Bit 2: Set for 640k conventional memory, clear for 512k + * Bit 1: Enable RAM beyond 1Mb. + * Bit 0: Enable EMS. + * + * The last value written to this port is saved at 0040:0093h, + * and in CMOS memory at offset 0x37. If the top bit of the + * CMOS byte is set, then high memory is being provided by + * an add-on card rather than the mainboard; accordingly, + * the BIOS will not allow high memory to be used as EMS. + * + * EMS is controlled by 16 page registers: + * + * Page mapped at 0xD000 0xD400 0xD800 0xDC00 + * ------------------------------------------------------ + * Pages 0x00-0x7F 0x208 0x4208 0x8208 0xc208 + * Pages 0x80-0xFF 0x218 0x4218 0x8218 0xc218 + * Pages 0x100-0x17F 0x258 0x4258 0x8258 0xc258 + * Pages 0x180-0x1FF 0x268 0x4268 0x8268 0xc268 + * + * The value written has bit 7 set to enable EMS, reset to + * disable it. + * + * So: + * OUT 0x208, 0x80 will page in the first 16k page at 0xD0000. + * OUT 0x208, 0x00 will page out EMS, leaving nothing at 0xD0000. + * OUT 0x4208, 0x80 will page in the first 16k page at 0xD4000. + * OUT 0x218, 0x80 will page in the 129th 16k page at 0xD0000. + * etc. + * + * To use EMS from DOS, you will need the Toshiba EMS driver + * (TOSHEMM.ZIP). This supports the above system, plus further + * ranges of ports at 0x_2A8, 0x_2B8, 0x_2C8. + * + * Features not implemented: + * > Four video fonts. + * > BIOS-controlled mapping of serial ports to IRQs. + * > Custom keyboard controller. This has a number of extra + * commands in the 0xB0-0xBC range, for such things as turbo + * on/off, and switching the keyboard between AT and PS/2 + * modes. Currently I have only implemented command 0xBB, + * so that self-test completes successfully. Commands include: + * + * 0xB0: Turbo on + * 0xB1: Turbo off + * 0xB2: Internal display on? + * 0xB3: Internal display off? + * 0xB5: Get settings byte (bottom bit is color/mono setting) + * 0xB6: Set settings byte + * 0xB7: Behave as 101-key PS/2 keyboard + * 0xB8: Behave as 84-key AT keyboard + * 0xBB: Return a byte, bit 2 is Fn key state, other bits unknown. + * + * The other main I/O port needed to POST is: + * 0x8084: System control. + * Top 3 bits give command, bottom 5 bits give parameters. + * 000 => set serial port IRQ / addresses + * bit 4: IRQ5 serial port base: 1 => 0x338, 0 => 0x3E8 + * bits 3, 2, 0 specify serial IRQs for COM1, COM2, COM3: + * 00 0 => 4, 3, 5 + * 00 1 => 4, 5, 3 + * 01 0 => 3, 4, 5 + * 01 1 => 3, 5, 4 + * 10 0 => 4, -, 3 + * 10 1 => 3, -, 4 + * 010 => set memory mappings + * bit 4 set if upper RAM is XMS + * bit 3 enable add-on memory boards beyond 5Mb? + * bit 2 set for 640k sysram, clear for 512k sysram + * bit 1 enable mainboard XMS + * bit 0 enable mainboard EMS + * 100 => set parallel mode / LCD settings + * bit 4 set for bidirectional parallel port + * bit 3 set to disable internal CGA + * bit 2 set for single-pixel LCD font + * bits 0,1 for display font + * + * Version: @(#)m_at_t3100e.c 1.0.3 2018/03/05 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ #include #include #include #include #include - #include "../86box.h" #include "../io.h" #include "../mouse.h" @@ -13,124 +159,18 @@ #include "../cpu/cpu.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" -#include "../video/vid_t3100e.h" - #include "machine.h" #include "m_at_t3100e.h" -/* The Toshiba 3100e is a 286-based portable. - * - * To bring up the BIOS setup screen hold down the 'Fn' key on booting - * - * Memory management - * ~~~~~~~~~~~~~~~~~ - * - * Motherboard memory is divided into: - * - Conventional memory: Either 512k or 640k - * - Upper memory: Either 512k or 384k, depending on amount of - * conventional memory. Upper memory can be - * used either as EMS or XMS. - * - High memory: 0-4Mb, depending on RAM installed. The BIOS - * setup screen allows some or all of this to be - * used as EMS; the remainder is XMS. - * - * Additional memory (either EMS or XMS) can also be provided by ISA - * expansion cards. - * - * Under test in PCEM, the BIOS will boot with up to 65368Kb of memory in - * total (16Mb less 16k). However it will give an error with RAM sizes - * above 8Mb, if any of the high memory is allocated as EMS, because the - * builtin EMS page registers can only access up to 8Mb. - * - * Memory is controlled by writes to I/O port 8084h: - * Bit 7: Always 0 } - * Bit 6: Always 1 } These bits select which motherboard function to - * Bit 5: Always 0 } access. - * Bit 4: Set to treat upper RAM as XMS - * Bit 3: Enable external RAM boards? - * Bit 2: Set for 640k conventional memory, clear for 512k - * Bit 1: Enable RAM beyond 1Mb. - * Bit 0: Enable EMS. - * - * The last value written to this port is saved at 0040:0093h, and in - * CMOS memory at offset 0x37. If the top bit of the CMOS byte is set, - * then high memory is being provided by an add-on card rather than the - * mainboard; accordingly, the BIOS will not allow high memory to be - * used as EMS. - * - * EMS is controlled by 16 page registers: - * - * Page mapped at 0xD000 0xD400 0xD800 0xDC00 - * ------------------------------------------------------ - * Pages 0x00-0x7F 0x208 0x4208 0x8208 0xc208 - * Pages 0x80-0xFF 0x218 0x4218 0x8218 0xc218 - * Pages 0x100-0x17F 0x258 0x4258 0x8258 0xc258 - * Pages 0x180-0x1FF 0x268 0x4268 0x8268 0xc268 - * - * The value written has bit 7 set to enable EMS, reset to disable it. - * - * So: OUT 0x208, 0x80 will page in the first 16k page at 0xD0000. - * OUT 0x208, 0x00 will page out EMS, leaving nothing at 0xD0000. - * OUT 0x4208, 0x80 will page in the first 16k page at 0xD4000. - * OUT 0x218, 0x80 will page in the 129th 16k page at 0xD0000. - * - * etc. - * - * To use EMS from DOS, you will need the Toshiba EMS driver (TOSHEMM.ZIP). - * This supports the above system, plus further ranges of ports at - * 0x_2A8, 0x_2B8, 0x_2C8. - * - */ - -static const int t3100e_log = 0; extern uint8_t *ram; /* Physical RAM */ -/* Features not implemented: - * > Four video fonts. - * > BIOS-controlled mapping of serial ports to IRQs. - * > Custom keyboard controller. This has a number of extra commands in the - * 0xB0-0xBC range, for such things as turbo on/off, and switching the - * keyboard between AT and PS/2 modes. Currently I have only implemented - * command 0xBB, so that self-test completes successfully. Commands include: - * - * 0xB0: Turbo on - * 0xB1: Turbo off - * 0xB2: Internal display on? - * 0xB3: Internal display off? - * 0xB5: Get settings byte (bottom bit is colour / mono setting) - * 0xB6: Set settings byte - * 0xB7: Behave as 101-key PS/2 keyboard - * 0xB8: Behave as 84-key AT keyboard - * 0xBB: Return a byte, bit 2 is Fn key state, other bits unknown. - * - * The other main I/O port needed to POST is: - * 0x8084: System control. - * Top 3 bits give command, bottom 5 bits give parameters. - * 000 => set serial port IRQ / addresses - * bit 4: IRQ5 serial port base: 1 => 0x338, 0 => 0x3E8 - * bits 3, 2, 0 specify serial IRQs for COM1, COM2, COM3: - * 00 0 => 4, 3, 5 - * 00 1 => 4, 5, 3 - * 01 0 => 3, 4, 5 - * 01 1 => 3, 5, 4 - * 10 0 => 4, -, 3 - * 10 1 => 3, -, 4 - * 010 => set memory mappings - * bit 4 set if upper RAM is XMS - * bit 3 enable add-on memory boards beyond 5Mb? - * bit 2 set for 640k sysram, clear for 512k sysram - * bit 1 enable mainboard XMS - * bit 0 enable mainboard EMS - * 100 => set parallel mode / LCD settings - * bit 4 set for bidirectional parallel port - * bit 3 set to disable internal CGA - * bit 2 set for single-pixel LCD font - * bits 0,1 for display font - */ - void at_init(); + +static const int t3100e_log = 0; + + /* The T3100e motherboard can (and does) dynamically reassign RAM between * conventional, XMS and EMS. This translates to monkeying with the mappings. */ diff --git a/src/machine/m_at_t3100e.h b/src/machine/m_at_t3100e.h index 0f3ac3093..0de5cf62a 100644 --- a/src/machine/m_at_t3100e.h +++ b/src/machine/m_at_t3100e.h @@ -1,7 +1,58 @@ -void t3100e_notify_set(uint8_t value); -void t3100e_display_set(uint8_t value); -uint8_t t3100e_display_get(); -uint8_t t3100e_config_get(); -void t3100e_turbo_set(uint8_t value); -uint8_t t3100e_mono_get(); -void t3100e_mono_set(uint8_t value); +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the Toshiba T3100e system. + * + * Version: @(#)m_at_t3100e.h 1.0.2 2018/03/05 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef MACHINE_T3100E_H +# define MACHINE_T3100E_H + + +extern device_t t3100e_device; + + +extern void t3100e_notify_set(uint8_t value); +extern void t3100e_display_set(uint8_t value); +extern uint8_t t3100e_display_get(void); +extern uint8_t t3100e_config_get(void); +extern void t3100e_turbo_set(uint8_t value); +extern uint8_t t3100e_mono_get(void); +extern void t3100e_mono_set(uint8_t value); + +extern void t3100e_video_options_set(uint8_t options); +extern void t3100e_display_set(uint8_t internal); + + +#endif /*MACHINE_T3100E_H*/ diff --git a/src/machine/m_at_t3100e_vid.c b/src/machine/m_at_t3100e_vid.c new file mode 100644 index 000000000..814d0dc3f --- /dev/null +++ b/src/machine/m_at_t3100e_vid.c @@ -0,0 +1,763 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Toshiba 3100e plasma display. + * This display has a fixed 640x400 resolution. + * + * T3100e CRTC regs (from the ROM): + * + * Selecting a character height of 3 seems to be sufficient to + * convert the 640x200 graphics mode to 640x400 (and, by + * analogy, 320x200 to 320x400). + * + * Horiz-----> Vert------> I ch + * 38 28 2D 0A 1F 06 19 1C 02 07 06 07 CO40 + * 71 50 5A 0A 1F 06 19 1C 02 07 06 07 CO80 + * 38 28 2D 0A 7F 06 64 70 02 01 06 07 Graphics + * 61 50 52 0F 19 06 19 19 02 0D 0B 0C MONO + * 2D 28 22 0A 67 00 64 67 02 03 06 07 640x400 + * + * Version: @(#)m_at_t3100e_vid.c 1.0.3 2018/03/07 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../cpu/cpu.h" +#include "../video/video.h" +#include "../video/vid_cga.h" +#include "m_at_t3100e.h" + + +#define T3100E_XSIZE 640 +#define T3100E_YSIZE 400 + + +/* Mapping of attributes to colours */ +static uint32_t amber, black; +static uint8_t boldcols[256]; /* Which attributes use the bold font */ +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 uint8_t st_video_options; +static int8_t st_display_internal = -1; + +void t3100e_video_options_set(uint8_t options) +{ + st_video_options = options; +} + +void t3100e_display_set(uint8_t internal) +{ + st_display_internal = internal; +} + +uint8_t t3100e_display_get() +{ + return st_display_internal; +} + + +typedef struct t3100e_t +{ + mem_mapping_t mapping; + + cga_t cga; /* The CGA is used for the external + * display; most of its registers are + * ignored by the plasma display. */ + + int font; /* Current font, 0-3 */ + int enabled; /* Hardware enabled, 0 or 1 */ + int internal; /* Using internal display? */ + uint8_t attrmap; /* Attribute mapping register */ + + int dispontime, dispofftime; + + int linepos, displine; + int vc; + int dispon; + int vsynctime; + uint8_t video_options; + + uint8_t *vram; +} t3100e_t; + + +void t3100e_recalctimings(t3100e_t *t3100e); +void t3100e_write(uint32_t addr, uint8_t val, void *p); +uint8_t t3100e_read(uint32_t addr, void *p); +void t3100e_recalcattrs(t3100e_t *t3100e); + + +void t3100e_out(uint16_t addr, uint8_t val, void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + switch (addr) + { + /* Emulated CRTC, register select */ + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + cga_out(addr, val, &t3100e->cga); + break; + + /* Emulated CRTC, value */ + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + /* Register 0x12 controls the attribute mappings for the + * plasma screen. */ + if (t3100e->cga.crtcreg == 0x12) + { + t3100e->attrmap = val; + t3100e_recalcattrs(t3100e); + return; + } + cga_out(addr, val, &t3100e->cga); + + t3100e_recalctimings(t3100e); + return; + + /* CGA control register */ + case 0x3D8: + cga_out(addr, val, &t3100e->cga); + return; + /* CGA colour register */ + case 0x3D9: + cga_out(addr, val, &t3100e->cga); + return; + } +} + +uint8_t t3100e_in(uint16_t addr, void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + uint8_t val; + + switch (addr) + { + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + if (t3100e->cga.crtcreg == 0x12) + { + val = t3100e->attrmap & 0x0F; + if (t3100e->internal) val |= 0x30; /* Plasma / CRT */ + return val; + } + } + + return cga_in(addr, &t3100e->cga); +} + + + + +void t3100e_write(uint32_t addr, uint8_t val, void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + egawrites++; + +// pclog("CGA_WRITE %04X %02X\n", addr, val); + t3100e->vram[addr & 0x7fff] = val; + cycles -= 4; +} + + + +uint8_t t3100e_read(uint32_t addr, void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + egareads++; + cycles -= 4; + +// pclog("CGA_READ %04X\n", addr); + return t3100e->vram[addr & 0x7fff]; +} + + + +void t3100e_recalctimings(t3100e_t *t3100e) +{ + double disptime; + double _dispontime, _dispofftime; + + if (!t3100e->internal) + { + cga_recalctimings(&t3100e->cga); + return; + } + disptime = 651; + _dispontime = 640; + _dispofftime = disptime - _dispontime; + t3100e->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + t3100e->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +/* Draw a row of text in 80-column mode */ +void t3100e_text_row80(t3100e_t *t3100e) +{ + uint32_t cols[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + 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; + + sc = (t3100e->displine) & 15; + addr = ((ma & ~1) + (t3100e->displine >> 4) * 80) * 2; + ma += (t3100e->displine >> 4) * 80; + + if ((t3100e->cga.crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((t3100e->cga.crtc[10] & 0x0F)*2 <= sc) && + ((t3100e->cga.crtc[11] & 0x0F)*2 >= sc); + } + for (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)); + + blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (t3100e->video_options & 4) + bold = boldcols[attr] ? chr + 256 : chr; + else + bold = boldcols[attr] ? chr : chr + 256; + bold += 512 * (t3100e->video_options & 3); + + if (t3100e->cga.cgamode & 0x20) /* Blink */ + { + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; + } + else + { + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + ++ma; + } +} + +/* Draw a row of text in 40-column mode */ +void t3100e_text_row40(t3100e_t *t3100e) +{ + uint32_t cols[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + 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; + + sc = (t3100e->displine) & 15; + addr = ((ma & ~1) + (t3100e->displine >> 4) * 40) * 2; + ma += (t3100e->displine >> 4) * 40; + + if ((t3100e->cga.crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((t3100e->cga.crtc[10] & 0x0F)*2 <= sc) && + ((t3100e->cga.crtc[11] & 0x0F)*2 >= sc); + } + for (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)); + + blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (t3100e->video_options & 4) + bold = boldcols[attr] ? chr + 256 : chr; + else bold = boldcols[attr] ? chr : chr + 256; + bold += 512 * (t3100e->video_options & 3); + + if (t3100e->cga.cgamode & 0x20) /* Blink */ + { + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; + } + else + { + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2 + 1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } + } + else + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2+1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + ++ma; + } +} + + + + +/* Draw a line in CGA 640x200 or T3100e 640x400 mode */ +void t3100e_cgaline6(t3100e_t *t3100e) +{ + int x, c; + uint8_t dat; + uint32_t ink = 0; + uint16_t addr; + 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; + + if (t3100e->cga.crtc[9] == 3) /* 640*400 */ + { + addr = ((t3100e->displine) & 1) * 0x2000 + + ((t3100e->displine >> 1) & 1) * 0x4000 + + (t3100e->displine >> 2) * 80 + + ((ma & ~1) << 1); + } + else + { + addr = ((t3100e->displine >> 1) & 1) * 0x2000 + + (t3100e->displine >> 2) * 80 + + ((ma & ~1) << 1); + } + for (x = 0; x < 80; x++) + { + dat = t3100e->vram[addr & 0x7FFF]; + addr++; + + for (c = 0; c < 8; c++) + { + ink = (dat & 0x80) ? fg : bg; + if (!(t3100e->cga.cgamode & 8)) ink = black; + ((uint32_t *)buffer32->line[t3100e->displine])[x*8+c] = ink; + dat = dat << 1; + } + } +} + + +/* Draw a line in CGA 320x200 mode. Here the CGA colours are converted to + * dither patterns: colour 1 to 25% grey, colour 2 to 50% grey */ +void t3100e_cgaline4(t3100e_t *t3100e) +{ + int x, c; + uint8_t dat, pattern; + uint32_t ink0 = 0, 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 */ + { + addr = ((t3100e->displine) & 1) * 0x2000 + + ((t3100e->displine >> 1) & 1) * 0x4000 + + (t3100e->displine >> 2) * 80 + + ((ma & ~1) << 1); + } + else /* 320*200 */ + { + addr = ((t3100e->displine >> 1) & 1) * 0x2000 + + (t3100e->displine >> 2) * 80 + + ((ma & ~1) << 1); + } + for (x = 0; x < 80; x++) + { + dat = t3100e->vram[addr & 0x7FFF]; + addr++; + + for (c = 0; c < 4; c++) + { + pattern = (dat & 0xC0) >> 6; + if (!(t3100e->cga.cgamode & 8)) pattern = 0; + + switch (pattern & 3) + { + case 0: ink0 = ink1 = black; break; + case 1: if (t3100e->displine & 1) + { + ink0 = black; ink1 = black; + } + else + { + ink0 = amber; ink1 = black; + } + break; + case 2: if (t3100e->displine & 1) + { + ink0 = black; ink1 = amber; + } + else + { + ink0 = amber; ink1 = black; + } + break; + case 3: ink0 = ink1 = amber; break; + + } + ((uint32_t *)buffer32->line[t3100e->displine])[x*8+2*c] = ink0; + ((uint32_t *)buffer32->line[t3100e->displine])[x*8+2*c+1] = ink1; + dat = dat << 2; + } + } +} + + + + + + +void t3100e_poll(void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + + if (t3100e->video_options != st_video_options) + { + t3100e->video_options = st_video_options; + + if (t3100e->video_options & 8) /* Disable internal CGA */ + mem_mapping_disable(&t3100e->mapping); + else mem_mapping_enable(&t3100e->mapping); + + /* Set the font used for the external display */ + t3100e->cga.fontbase = (512 * (t3100e->video_options & 3)) + + ((t3100e->video_options & 4) ? 256 : 0); + + } + /* Switch between internal plasma and external CRT display. */ + if (st_display_internal != -1 && st_display_internal != t3100e->internal) + { + t3100e->internal = st_display_internal; + t3100e_recalctimings(t3100e); + } + if (!t3100e->internal) + { + cga_poll(&t3100e->cga); + return; + } + + + if (!t3100e->linepos) + { + t3100e->cga.vidtime += t3100e->dispofftime; + t3100e->cga.cgastat |= 1; + t3100e->linepos = 1; + if (t3100e->dispon) + { + if (t3100e->displine == 0) + { + video_wait_for_buffer(); + } + + /* Graphics */ + if (t3100e->cga.cgamode & 0x02) + { + if (t3100e->cga.cgamode & 0x10) + t3100e_cgaline6(t3100e); + else t3100e_cgaline4(t3100e); + } + else + if (t3100e->cga.cgamode & 0x01) /* High-res text */ + { + t3100e_text_row80(t3100e); + } + else + { + t3100e_text_row40(t3100e); + } + } + t3100e->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (t3100e->displine == 400) /* Start of VSYNC */ + { + t3100e->cga.cgastat |= 8; + t3100e->dispon = 0; + } + if (t3100e->displine == 416) /* End of VSYNC */ + { + t3100e->displine = 0; + t3100e->cga.cgastat &= ~8; + t3100e->dispon = 1; + } + } + else + { + if (t3100e->dispon) + { + t3100e->cga.cgastat &= ~1; + } + t3100e->cga.vidtime += t3100e->dispontime; + t3100e->linepos = 0; + + if (t3100e->displine == 400) + { +/* Hardcode 640x400 window size */ + if (T3100E_XSIZE != xsize || T3100E_YSIZE != ysize) + { + xsize = T3100E_XSIZE; + ysize = T3100E_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 640x400 resolution */ + video_res_x = T3100E_XSIZE; + video_res_y = T3100E_YSIZE; + + if (t3100e->cga.cgamode & 0x02) + { + if (t3100e->cga.cgamode & 0x10) + video_bpp = 1; + else video_bpp = 2; + + } + else video_bpp = 0; + t3100e->cga.cgablink++; + } + } +} + + + +void t3100e_recalcattrs(t3100e_t *t3100e) +{ + 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(0xf7, 0x7C, 0x34); + black = makecol(0x17, 0x0C, 0x00); + + /* Initialise the attribute mapping. Start by defaulting everything + * to black on amber, and with bold set by bit 3 */ + for (n = 0; n < 256; n++) + { + boldcols[n] = (n & 8) != 0; + 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 (t3100e->attrmap & 4) /* 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; + } + if (t3100e->attrmap & 8) boldcols[n] = 1; /* Bold */ + } + /* 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 (t3100e->attrmap & 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; + } + if (t3100e->attrmap & 2) boldcols[n] = 1; + } + /* 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; + boldcols[n] = (n & 0x08) != 0; + } + + + /* 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; + } +} + + +void *t3100e_init(device_t *info) +{ + t3100e_t *t3100e = malloc(sizeof(t3100e_t)); + memset(t3100e, 0, sizeof(t3100e_t)); + cga_init(&t3100e->cga); + + t3100e->internal = 1; + + /* 32k video RAM */ + t3100e->vram = malloc(0x8000); + + timer_add(t3100e_poll, &t3100e->cga.vidtime, TIMER_ALWAYS_ENABLED, t3100e); + + /* Occupy memory between 0xB8000 and 0xBFFFF */ + mem_mapping_add(&t3100e->mapping, 0xb8000, 0x8000, t3100e_read, NULL, NULL, t3100e_write, NULL, NULL, NULL, 0, t3100e); + /* Respond to CGA I/O ports */ + io_sethandler(0x03d0, 0x000c, t3100e_in, NULL, NULL, t3100e_out, NULL, NULL, t3100e); + + /* Default attribute mapping is 4 */ + t3100e->attrmap = 4; + t3100e_recalcattrs(t3100e); + +/* Start off in 80x25 text mode */ + t3100e->cga.cgastat = 0xF4; + t3100e->cga.vram = t3100e->vram; + t3100e->enabled = 1; + t3100e->video_options = 0xFF; + return t3100e; +} + +void t3100e_close(void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + + free(t3100e->vram); + free(t3100e); +} + +void t3100e_speed_changed(void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + + t3100e_recalctimings(t3100e); +} + +device_t t3100e_device = +{ + "Toshiba T3100e", + 0, + 0, + t3100e_init, + t3100e_close, + NULL, + NULL, + t3100e_speed_changed, + NULL, + NULL +}; diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index 614ef122a..f2dae9a28 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -1,10 +1,10 @@ /* - * 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. + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. * - * This file is part of the 86Box distribution. + * This file is part of the VARCem Project. * * Implementation of the Schneider EuroPC system. * @@ -27,8 +27,7 @@ * f000:ecc5 801a video setup error * f000:d6c9 copyright output * f000:e1b7 - * f000:e1be DI bits set mean output text!!!, - * (801a) + * f000:e1be DI bits set mean output text!!! (801a) * f000: 0x8000 output * 1 rtc error * 2 rtc time or date error @@ -53,21 +52,23 @@ * output cl at jim 0xa * write ah hinibble as lownibble into jim 0xa * write ah lownibble into jim 0xa - * f000:ef66 RTC read reg cl + * f000:ef66 RTC read reg cl * polls until jim 0xa is zero, * output cl at jim 0xa * read low 4 nibble at jim 0xa * read low 4 nibble at jim 0xa * return first nibble<<4|second nibble in ah - * f000:f046 seldom compares ret - * f000:fe87 0 -> ds - * 0000:0469 bit 0: b0000 memory available + * f000:f046 seldom compares ret + * f000:fe87 0 -> ds + * + * Memory: + * 0000:0469 bit 0: b0000 memory available * bit 1: b8000 memory available - * 0000:046a: 00 jim 250 01 jim 350 + * 0000:046a: 00 jim 250 01 jim 350 * * WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK. * - * Version: @(#)europc.c 1.0.6 2018/01/16 + * Version: @(#)europc.c 1.0.2 2018/03/11 * * Author: Fred N. van Kempen, * @@ -77,12 +78,43 @@ * input from people with real EuroPC hardware. * * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include +#include #include "../86box.h" #include "../io.h" #include "../nmi.h" @@ -90,17 +122,17 @@ #include "../rom.h" #include "../nvr.h" #include "../device.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../disk/hdc.h" #include "../keyboard.h" #include "../mouse.h" #include "../game/gameport.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../disk/hdc.h" #include "../video/video.h" #include "machine.h" -#define EUROPC_DEBUG 1 /* current debugging level */ +#define EUROPC_DEBUG 0 /* current debugging level */ /* M3002 RTC chip registers. */ @@ -109,7 +141,7 @@ #define MRTC_HOURS 0x02 /* BCD, 00-23 */ #define MRTC_DAYS 0x03 /* BCD, 01-31 */ #define MRTC_MONTHS 0x04 /* BCD, 01-12 */ -#define MRTC_YEARS 0x05 /* BCD, 00-99 (2017 is 0x17) */ +#define MRTC_YEARS 0x05 /* BCD, 00-99 (year only) */ #define MRTC_WEEKDAY 0x06 /* BCD, 01-07 */ #define MRTC_WEEKNO 0x07 /* BCD, 01-52 */ #define MRTC_CONF_A 0x08 /* EuroPC config, binary */ @@ -121,127 +153,232 @@ #define MRTC_CHECK_HI 0x0e /* Checksum, high byte */ #define MRTC_CTRLSTAT 0x0f /* RTC control/status, binary */ - typedef struct { uint16_t jim; /* JIM base address */ uint8_t regs[16]; /* JIM internal regs (8) */ - struct { - uint8_t dat[16]; - uint8_t stat; - uint8_t addr; - } rtc; - - nvr_t nvr; /* 86Box NVR */ -} vm_t; + nvr_t nvr; /* NVR */ + uint8_t nvr_stat; + uint8_t nvr_addr; +} europc_t; -static vm_t *vm = NULL; +static europc_t europc; -/* Load the relevant portion of the NVR to disk. */ -static int8_t -load_nvr(wchar_t *fn) -{ - FILE *f; - - if (vm == NULL) return(0); - - f = nvr_fopen(fn, L"rb"); - if (f != NULL) { - (void)fread(vm->rtc.dat, 1, 16, f); - (void)fclose(f); - pclog("EuroPC: CMOS data loaded from file %ls !\n", fn); - return(1); - } - - pclog("EuroPC: unable to load NVR !\n"); - return(0); -} - - -/* Save the relevant portion of the NVR to disk. */ -static int8_t -save_nvr(wchar_t *fn) -{ - FILE *f; - - if (vm == NULL) return(0); - - f = nvr_fopen(fn, L"wb"); - if (f != NULL) { - (void)fwrite(vm->rtc.dat, 1, 16, f); - (void)fclose(f); - return(1); - } - - pclog("EuroPC: unable to save NVR !\n"); - return(0); -} - - -/* This is called every second through the NVR/RTC hook. */ +/* + * This is called every second through the NVR/RTC hook. + * + * We fake a 'running' RTC by updating its registers on + * each passing second. Not exactly accurate, but good + * enough. + * + * Note that this code looks nasty because of all the + * BCD to decimal vv going on. + * + * FIXME: should we mark NVR as dirty? + */ static void -rtc_hook(nvr_t *nvr) +rtc_tick(nvr_t *nvr) { -#if 0 - int month, year; + uint8_t *regs; + int mon, yr; - sys->rtc.dat[0] = bcd_adjust(sys->rtc.dat[0]+1); - if (sys->rtc.dat[0] >= 0x60) { - sys->rtc.dat[0] = 0; - sys->rtc.dat[1] = bcd_adjust(sys->rtc.dat[1]+1); - if (sys->rtc.dat[1] >= 0x60) { - sys->rtc.dat[1] = 0; - sys->rtc.dat[2] = bcd_adjust(sys->rtc.dat[2]+1); - if (sys->rtc.dat[2] >= 0x24) { - sys->rtc.dat[2] = 0; - sys->uropc_rtc.data[3]=bcd_adjust(sys->uropc_rtc.data[3]+1); - month = bcd_2_dec(sys->rtc.dat[4]); + /* Only if RTC is running.. */ + regs = nvr->regs; + if (! (regs[MRTC_CTRLSTAT] & 0x01)) return; - /* Save for julian_days_in_month_calculation. */ - year = bcd_2_dec(sys->rtc.dat[5])+2000; - if (sys->rtc.dat[3] > gregorian_days_in_month(month, year)) { - sys->rtc.dat[3] = 1; - sys->rtc.dat[4] = bcd_adjust(sys->rtc.dat[4]+1); - if (sys->rtc.dat[4]>0x12) { - sys->rtc.dat[4] = 1; - sys->rtc.dat[5] = bcd_adjust(sys->rtc.dat[5]+1)&0xff; - } + regs[MRTC_SECONDS] = RTC_BCDINC(nvr->regs[MRTC_SECONDS], 1); + if (regs[MRTC_SECONDS] >= RTC_BCD(60)) { + regs[MRTC_SECONDS] = RTC_BCD(0); + regs[MRTC_MINUTES] = RTC_BCDINC(regs[MRTC_MINUTES], 1); + if (regs[MRTC_MINUTES] >= RTC_BCD(60)) { + regs[MRTC_MINUTES] = RTC_BCD(0); + regs[MRTC_HOURS] = RTC_BCDINC(regs[MRTC_HOURS], 1); + if (regs[MRTC_HOURS] >= RTC_BCD(24)) { + regs[MRTC_HOURS] = RTC_BCD(0); + regs[MRTC_DAYS] = RTC_BCDINC(regs[MRTC_DAYS], 1); + mon = RTC_DCB(regs[MRTC_MONTHS]); + yr = RTC_DCB(regs[MRTC_YEARS]) + 1900; + if (RTC_DCB(regs[MRTC_DAYS]) > nvr_get_days(mon, yr)) { + regs[MRTC_DAYS] = RTC_BCD(1); + regs[MRTC_MONTHS] = RTC_BCDINC(regs[MRTC_MONTHS], 1); + if (regs[MRTC_MONTHS] > RTC_BCD(12)) { + regs[MRTC_MONTHS] = RTC_BCD(1); + regs[MRTC_YEARS] = RTC_BCDINC(regs[MRTC_YEARS], 1) & 0xff; } } } } } +} + + +/* Get the current NVR time. */ +static void +rtc_time_get(uint8_t *regs, struct tm *tm) +{ + /* NVR is in BCD data mode. */ + tm->tm_sec = RTC_DCB(regs[MRTC_SECONDS]); + tm->tm_min = RTC_DCB(regs[MRTC_MINUTES]); + tm->tm_hour = RTC_DCB(regs[MRTC_HOURS]); + tm->tm_wday = (RTC_DCB(regs[MRTC_WEEKDAY]) - 1); + tm->tm_mday = RTC_DCB(regs[MRTC_DAYS]); + tm->tm_mon = (RTC_DCB(regs[MRTC_MONTHS]) - 1); + tm->tm_year = RTC_DCB(regs[MRTC_YEARS]); +#if USE_Y2K + tm->tm_year += (RTC_DCB(regs[MRTC_CENTURY]) * 100) - 1900; #endif } +/* Set the current NVR time. */ +static void +rtc_time_set(uint8_t *regs, struct tm *tm) +{ + /* NVR is in BCD data mode. */ + regs[MRTC_SECONDS] = RTC_BCD(tm->tm_sec); + regs[MRTC_MINUTES] = RTC_BCD(tm->tm_min); + regs[MRTC_HOURS] = RTC_BCD(tm->tm_hour); + regs[MRTC_WEEKDAY] = RTC_BCD(tm->tm_wday + 1); + regs[MRTC_DAYS] = RTC_BCD(tm->tm_mday); + regs[MRTC_MONTHS] = RTC_BCD(tm->tm_mon + 1); + regs[MRTC_YEARS] = RTC_BCD(tm->tm_year % 100); +#if USE_Y2K + regs[MRTC_CENTURY] = RTC_BCD((tm->tm_year+1900) / 100); +#endif +} + + +static void +rtc_start(nvr_t *nvr) +{ + struct tm tm; + + /* Initialize the internal and chip times. */ + if (enable_sync) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + rtc_time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + rtc_time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } + #if 0 -void europc_rtc_init(void) -{ - europc_rtc.data[0xf]=1; - - europc_rtc.timer = timer_alloc(europc_rtc_timer); - timer_adjust(europc_rtc.timer, 0, 0, 1.0); -} + /* Start the RTC - BIOS will do this. */ + nvr->regs[MRTC_CTRLSTAT] = 0x01; #endif +} + + +/* Create a valid checksum for the current NVR data. */ +static uint8_t +rtc_checksum(uint8_t *ptr) +{ + uint8_t sum; + int i; + + /* Calculate all bytes with XOR. */ + sum = 0x00; + for (i=MRTC_CONF_A; i<=MRTC_CONF_E; i++) + sum += ptr[i]; + + return(sum); +} + + +/* Reset the machine's NVR to a sane state. */ +static void +rtc_reset(nvr_t *nvr) +{ + /* Initialize the RTC to a known state. */ + nvr->regs[MRTC_SECONDS] = RTC_BCD(0); /* seconds */ + nvr->regs[MRTC_MINUTES] = RTC_BCD(0); /* minutes */ + nvr->regs[MRTC_HOURS] = RTC_BCD(0); /* hours */ + nvr->regs[MRTC_DAYS] = RTC_BCD(1); /* days */ + nvr->regs[MRTC_MONTHS] = RTC_BCD(1); /* months */ + nvr->regs[MRTC_YEARS] = RTC_BCD(80); /* years */ + nvr->regs[MRTC_WEEKDAY] = RTC_BCD(1); /* weekday */ + nvr->regs[MRTC_WEEKNO] = RTC_BCD(1); /* weekno */ + + /* + * EuroPC System Configuration: + * + * [A] unknown + * + * [B] 7 1 bootdrive extern + * 0 bootdribe intern + * 6:5 11 invalid hard disk type + * 10 hard disk installed, type 2 + * 01 hard disk installed, type 1 + * 00 hard disk not installed + * 4:3 11 invalid external drive type + * 10 external drive 720K + * 01 external drive 360K + * 00 external drive disabled + * 2 unknown + * 1:0 11 invalid internal drive type + * 10 internal drive 360K + * 01 internal drive 720K + * 00 internal drive disabled + * + * [C] 7:6 unknown + * 5 monitor detection OFF + * 4 unknown + * 3:2 11 illegal memory size + * 10 512K + * 01 256K + * 00 640K + * 1:0 11 illegal game port + * 10 gameport as mouse port + * 01 gameport as joysticks + * 00 gameport disabled + * + * [D] 7:6 10 9MHz CPU speed + * 01 7MHz CPU speed + * 00 4.77 MHz CPU + * 5 unknown + * 4 external: color, internal: mono + * 3 unknown + * 2 internal video ON + * 1:0 11 mono + * 10 color80 + * 01 color40 + * 00 special (EGA,VGA etc) + * + * [E] 7:4 unknown + * 3:0 country (00=Deutschland, 0A=ASCII) + */ + nvr->regs[MRTC_CONF_A] = 0x00; /* CONFIG A */ + nvr->regs[MRTC_CONF_B] = 0x0A; /* CONFIG B */ + nvr->regs[MRTC_CONF_C] = 0x28; /* CONFIG C */ + nvr->regs[MRTC_CONF_D] = 0x12; /* CONFIG D */ + nvr->regs[MRTC_CONF_E] = 0x0A; /* CONFIG E */ + + nvr->regs[MRTC_CHECK_LO] = 0x00; /* checksum (LO) */ + nvr->regs[MRTC_CHECK_HI] = 0x00; /* checksum (HI) */ + + nvr->regs[MRTC_CTRLSTAT] = 0x01; /* status/control */ + + /* Generate a valid checksum. */ + nvr->regs[MRTC_CHECK_LO] = rtc_checksum(nvr->regs); +} /* Execute a JIM control command. */ static void -jim_action(vm_t *sys, uint8_t reg, uint8_t val) +jim_set(europc_t *sys, uint8_t reg, uint8_t val) { switch(reg) { case 0: /* MISC control (WO) */ -//pclog("EuroPC: write MISC = %02x\n", val); // bit0: enable MOUSE // bit1: enable joystick break; case 2: /* AGA control */ -//pclog("EuroPC: write AGA = %02x\n", val); if (! (val & 0x80)) { /* Reset AGA. */ break; @@ -276,7 +413,6 @@ jim_action(vm_t *sys, uint8_t reg, uint8_t val) break; case 4: /* CPU Speed control */ -//pclog("EuroPC: write CPUCLK = %02x\n", val); switch(val & 0xc0) { case 0x00: /* 4.77 MHz */ // cpu_set_clockscale(0, 1.0/2); @@ -304,7 +440,7 @@ jim_action(vm_t *sys, uint8_t reg, uint8_t val) static void jim_write(uint16_t addr, uint8_t val, void *priv) { - vm_t *sys = (vm_t *)priv; + europc_t *sys = (europc_t *)priv; uint8_t b; #if EUROPC_DEBUG > 1 @@ -320,28 +456,30 @@ jim_write(uint16_t addr, uint8_t val, void *priv) case 0x05: case 0x06: case 0x07: - jim_action(sys, (addr & 0x07), val); + jim_set(sys, (addr & 0x07), val); break; - case 0x0A: /* M3002 RTC INDEX/DATA register */ - switch(sys->rtc.stat) { + case 0x0a: /* M3002 RTC INDEX/DATA register */ + switch(sys->nvr_stat) { case 0: /* save index */ - sys->rtc.addr = val & 0x0f; - sys->rtc.stat++; + sys->nvr_addr = val & 0x0f; + sys->nvr_stat++; break; case 1: /* save data HI nibble */ - b = sys->rtc.dat[sys->rtc.addr] & 0x0f; + b = sys->nvr.regs[sys->nvr_addr] & 0x0f; b |= (val << 4); - sys->rtc.dat[sys->rtc.addr] = b; - sys->rtc.stat++; + sys->nvr.regs[sys->nvr_addr] = b; + sys->nvr_stat++; + nvr_dosave++; break; case 2: /* save data LO nibble */ - b = sys->rtc.dat[sys->rtc.addr] & 0xf0; + b = sys->nvr.regs[sys->nvr_addr] & 0xf0; b |= (val & 0x0f); - sys->rtc.dat[sys->rtc.addr] = b; - sys->rtc.stat = 0; + sys->nvr.regs[sys->nvr_addr] = b; + sys->nvr_stat = 0; + nvr_dosave++; break; } break; @@ -357,7 +495,7 @@ jim_write(uint16_t addr, uint8_t val, void *priv) static uint8_t jim_read(uint16_t addr, void *priv) { - vm_t *sys = (vm_t *)priv; + europc_t *sys = (europc_t *)priv; uint8_t r = 0xff; switch (addr & 0x000f) { @@ -375,20 +513,20 @@ jim_read(uint16_t addr, void *priv) r = sys->regs[addr & 0x07]; break; - case 0x0A: /* M3002 RTC INDEX/DATA register */ - switch(sys->rtc.stat) { + case 0x0a: /* M3002 RTC INDEX/DATA register */ + switch(sys->nvr_stat) { case 0: r = 0x00; break; case 1: /* read data HI nibble */ - r = (sys->rtc.dat[sys->rtc.addr] >> 4); - sys->rtc.stat++; + r = (sys->nvr.regs[sys->nvr_addr] >> 4); + sys->nvr_stat++; break; case 2: /* read data LO nibble */ - r = (sys->rtc.dat[sys->rtc.addr] & 0x0f); - sys->rtc.stat = 0; + r = (sys->nvr.regs[sys->nvr_addr] & 0x0f); + sys->nvr_stat = 0; break; } break; @@ -406,120 +544,29 @@ jim_read(uint16_t addr, void *priv) } -static uint8_t -rtc_checksum(uint8_t *ptr) -{ - uint8_t sum; - int i; - - /* Calculate all bytes with XOR. */ - sum = 0x00; - for (i=MRTC_CONF_A; i<=MRTC_CONF_E; i++) - sum += ptr[i]; - - return(sum); -} - - -/* - * Initialize the mainboard 'device' of the machine. - */ +/* Initialize the mainboard 'device' of the machine. */ static void * europc_boot(device_t *info) { - vm_t *sys = vm; + europc_t *sys = &europc; uint8_t b; #if EUROPC_DEBUG pclog("EuroPC: booting mainboard..\n"); #endif - /* Try to load the NVR from file. */ - if (! nvr_load()) { - /* Load failed, reset to defaults. */ - sys->rtc.dat[0x00] = 0x00; /* RTC seconds */ - sys->rtc.dat[0x01] = 0x00; /* RTC minutes */ - sys->rtc.dat[0x02] = 0x00; /* RTC hours */ - sys->rtc.dat[0x03] = 0x01; /* RTC days */ - sys->rtc.dat[0x04] = 0x01; /* RTC months */ - sys->rtc.dat[0x05] = 0x17; /* RTC years */ - sys->rtc.dat[0x06] = 0x01; /* RTC weekday */ - sys->rtc.dat[0x07] = 0x01; /* RTC weekno */ - - /* - * EuroPC System Configuration: - * - * [A] unknown - * - * [B] 7 1 bootdrive extern - * 0 bootdribe intern - * 6:5 11 invalid hard disk type - * 10 hard disk installed, type 2 - * 01 hard disk installed, type 1 - * 00 hard disk not installed - * 4:3 11 invalid external drive type - * 10 external drive 720K - * 01 external drive 360K - * 00 external drive disabled - * 2 unknown - * 1:0 11 invalid internal drive type - * 10 internal drive 360K - * 01 internal drive 720K - * 00 internal drive disabled - * - * [C] 7:6 unknown - * 5 monitor detection OFF - * 4 unknown - * 3:2 11 illegal memory size - * 10 512K - * 01 256K - * 00 640K - * 1:0 11 illegal game port - * 10 gameport as mouse port - * 01 gameport as joysticks - * 00 gameport disabled - * - * [D] 7:6 10 9MHz CPU speed - * 01 7MHz CPU speed - * 00 4.77 MHz CPU - * 5 unknown - * 4 external: color, internal: mono - * 3 unknown - * 2 internal video ON - * 1:0 11 mono - * 10 color80 - * 01 color40 - * 00 special (EGA,VGA etc) - * - * [E] 7:4 unknown - * 3:0 country (00=Deutschland, 0A=ASCII) - */ - sys->rtc.dat[MRTC_CONF_A] = 0x00; /* CONFIG A */ - sys->rtc.dat[MRTC_CONF_B] = 0x0A; /* CONFIG B */ - sys->rtc.dat[MRTC_CONF_C] = 0x28; /* CONFIG C */ - sys->rtc.dat[MRTC_CONF_D] = 0x12; /* CONFIG D */ - sys->rtc.dat[MRTC_CONF_E] = 0x0A; /* CONFIG E */ - - sys->rtc.dat[MRTC_CHECK_LO] = 0x44; /* checksum (LO) */ - sys->rtc.dat[MRTC_CHECK_HI] = 0x00; /* checksum (HI) */ - - sys->rtc.dat[MRTC_CTRLSTAT] = 0x01; /* status/control */ - - /* Provide correct checksum. */ - sys->rtc.dat[MRTC_CHECK_LO] = rtc_checksum(sys->rtc.dat); - } pclog("EuroPC: NVR=[ %02x %02x %02x %02x %02x ] %sVALID\n", - sys->rtc.dat[MRTC_CONF_A], sys->rtc.dat[MRTC_CONF_B], - sys->rtc.dat[MRTC_CONF_C], sys->rtc.dat[MRTC_CONF_D], - sys->rtc.dat[MRTC_CONF_E], - (sys->rtc.dat[MRTC_CHECK_LO]!=rtc_checksum(sys->rtc.dat))?"IN":""); + sys->nvr.regs[MRTC_CONF_A], sys->nvr.regs[MRTC_CONF_B], + sys->nvr.regs[MRTC_CONF_C], sys->nvr.regs[MRTC_CONF_D], + sys->nvr.regs[MRTC_CONF_E], + (sys->nvr.regs[MRTC_CHECK_LO]!=rtc_checksum(sys->nvr.regs))?"IN":""); /* * Now that we have initialized the NVR (either from file, * or by setting it to defaults) we can start overriding it - * with values set by the 86Box user. + * with values set by the user. */ - b = (sys->rtc.dat[MRTC_CONF_D] & ~0x17); + b = (sys->nvr.regs[MRTC_CONF_D] & ~0x17); switch(gfxcard) { case GFX_CGA: /* Color, CGA */ case GFX_COLORPLUS: /* Color, Hercules ColorPlus */ @@ -536,10 +583,10 @@ europc_boot(device_t *info) b |= 0x10; /* external video, special */ } - sys->rtc.dat[MRTC_CONF_D] = b; + sys->nvr.regs[MRTC_CONF_D] = b; /* Update the memory size. */ - b = (sys->rtc.dat[MRTC_CONF_C] & 0xf3); + b = (sys->nvr.regs[MRTC_CONF_C] & 0xf3); switch(mem_size) { case 256: b |= 0x04; @@ -553,10 +600,10 @@ europc_boot(device_t *info) b |= 0x00; break; } - sys->rtc.dat[MRTC_CONF_C] = b; + sys->nvr.regs[MRTC_CONF_C] = b; /* Update CPU speed. */ - b = (sys->rtc.dat[MRTC_CONF_D] & 0x3f); + b = (sys->nvr.regs[MRTC_CONF_D] & 0x3f); switch(cpu) { case 0: /* 8088, 4.77 MHz */ b |= 0x00; @@ -570,26 +617,26 @@ europc_boot(device_t *info) b |= 0x80; break; } - sys->rtc.dat[MRTC_CONF_D] = b; + sys->nvr.regs[MRTC_CONF_D] = b; /* Set up game port. */ - b = (sys->rtc.dat[MRTC_CONF_C] & 0xfc); + b = (sys->nvr.regs[MRTC_CONF_C] & 0xfc); if (mouse_type == MOUSE_TYPE_LOGIBUS) { b |= 0x01; /* enable port as MOUSE */ } else if (joystick_type != 7) { b |= 0x02; /* enable port as joysticks */ device_add(&gameport_device); } - sys->rtc.dat[MRTC_CONF_C] = b; + sys->nvr.regs[MRTC_CONF_C] = b; #if 0 /* Set up floppy types. */ - sys->rtc.dat[MRTC_CONF_B] = 0x2A; + sys->nvr.regs[MRTC_CONF_B] = 0x2a; #endif - /* Validate the NVR checksum. */ - sys->rtc.dat[MRTC_CHECK_LO] = rtc_checksum(sys->rtc.dat); - nvr_save(); + /* Validate the NVR checksum and save. */ + sys->nvr.regs[MRTC_CHECK_LO] = rtc_checksum(sys->nvr.regs); + nvr_dosave++; /* * Allocate the system's I/O handlers. @@ -600,11 +647,10 @@ europc_boot(device_t *info) * the way of other cards that need this range. */ io_sethandler(sys->jim, 16, - jim_read, NULL, NULL, - jim_write, NULL, NULL, sys); + jim_read,NULL,NULL, jim_write,NULL,NULL, sys); /* Only after JIM has been initialized. */ - device_add(&keyboard_xt_device); + (void)device_add(&keyboard_xt_device); /* * Set up and enable the HD20 disk controller. @@ -612,7 +658,7 @@ europc_boot(device_t *info) * We only do this if we have not configured another one. */ if (hdc_current == 1) - device_add(&europc_hdc_device); + (void)device_add(&europc_hdc_device); return(sys); } @@ -621,13 +667,10 @@ europc_boot(device_t *info) static void europc_close(void *priv) { - nvr_t *nvr = &vm->nvr; + nvr_t *nvr = &europc.nvr; - if (nvr->fname != NULL) - free(nvr->fname); - - free(vm); - vm = NULL; + if (nvr->fn != NULL) + free(nvr->fn); } @@ -655,9 +698,7 @@ static device_config_t europc_config[] = { device_t europc_device = { "EuroPC System Board", 0, 0, - europc_boot, /* init */ - europc_close, /* close */ - NULL, + europc_boot, europc_close, NULL, NULL, NULL, NULL, NULL, europc_config }; @@ -674,36 +715,28 @@ device_t europc_device = { void machine_europc_init(machine_t *model) { - vm_t *sys; - - /* Allocate machine data. */ - sys = (vm_t *)malloc(sizeof(vm_t)); - if (sys == NULL) { - pclog("EuroPC: unable to allocate machine data!\n"); - return; - } - memset(sys, 0x00, sizeof(vm_t)); - sys->jim = 0x0250; - vm = sys; + /* Clear the machine state. */ + memset(&europc, 0x00, sizeof(europc_t)); + europc.jim = 0x0250; machine_common_init(model); nmi_init(); mem_add_bios(); /* This is machine specific. */ - vm->nvr.mask = model->nvrmask; - vm->nvr.irq = -1; + europc.nvr.size = model->nvrmask + 1; + europc.nvr.irq = -1; /* Set up any local handlers here. */ - vm->nvr.load = load_nvr; - vm->nvr.save = save_nvr; - vm->nvr.hook = rtc_hook; + europc.nvr.reset = rtc_reset; + europc.nvr.start = rtc_start; + europc.nvr.tick = rtc_tick; /* Initialize the actual NVR. */ - nvr_init(&vm->nvr); + nvr_init(&europc.nvr); /* Enable and set up the FDC. */ - device_add(&fdc_xt_device); + (void)device_add(&fdc_xt_device); /* Enable and set up the mainboard device. */ device_add(&europc_device); diff --git a/src/machine/m_europc_hdc.c b/src/machine/m_europc_hdc.c index 4fb8a3dfd..ef8b21514 100644 --- a/src/machine/m_europc_hdc.c +++ b/src/machine/m_europc_hdc.c @@ -1,10 +1,10 @@ /* - * 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. + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. * - * This file is part of the 86Box distribution. + * This file is part of the VARCem Project. * * Implementation of the EuroPC HD20 internal controller. * @@ -20,13 +20,45 @@ * This driver is based on the information found in the IBM-PC * Technical Reference manual, pp 187 and on. * - * Version: @(#)europc_hdc.c 1.0.2 2017/11/18 - * - * Author: Fred N. van Kempen, * Based on the original "xebec.c" from Sarah Walker. * + * Version: @(#)m_europc_hdc.c 1.0.2 2018/03/11 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. * Copyright 2008-2017 Sarah Walker. - * Copyright 2017 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE @@ -44,11 +76,12 @@ #include "../timer.h" #include "../disk/hdc.h" #include "../disk/hdd.h" +#include "../plat.h" #include "../ui.h" #include "machine.h" -#define HDC_DEBUG 1 +#define HDC_DEBUG 0 #define HDC_NEWPARAMS 1 /* use NEW parameter block */ #define HDD_IOADDR 0x0320 diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index 0301fcedb..b1d5c2367 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -1,675 +1,978 @@ -#include -#include -#include -#include -#include -#include "../86box.h" -#include "../device.h" -#include "../io.h" -#include "../keyboard.h" -#include "../lpt.h" -#include "../mem.h" -#include "../nmi.h" -#include "../nvr.h" -#include "../nvr_tc8521.h" -#include "../pit.h" -#include "../plat.h" -#include "../rom.h" -#include "../cpu/cpu.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../game/gameport.h" -#include "../video/vid_t1000.h" -#include "machine.h" - -/* The T1000 is the T3100e's little brother -- a real laptop with a - * rechargeable battery. - * - * Features: 80C88 at 4.77MHz - * 512k system RAM - * 640x200 monochrome LCD - * 82-key keyboard - * Real-time clock. Not the normal 146818, but a TC8521, which - * is a 4-bit chip. - * A ROM drive (128k, 256k or 512k) which acts as a mini hard - * drive and contains a copy of DOS 2.11. - * 160 bytes of non-volatile RAM for the CONFIG.SYS used when - * booting from the ROM drive. Possibly physically located - * in the keyboard controller RAM. - * - * An optional memory expansion board can be fitted. This adds 768k of RAM, - * which can be used for up to three purposes: - * > Conventional memory -- 128k between 512k and 640k - * > HardRAM -- a battery-backed RAM drive. - * > EMS - * - * This means that there are up to three different implementations of - * non-volatile RAM in the same computer (52 nibbles in the TC8521, 160 - * bytes of CONFIG.SYS, and up to 768k of HardRAM). - * - * The T1200 is a slightly upgraded version with a turbo mode (double CPU - * clock, 9.54MHz) and an optional hard drive. The interface for this is - * proprietary both at the physical and programming level. - * - * 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb] or 0Dh [10Mb]. - * - */ - -void common_init(); - -uint8_t config_sys[160]; - -static struct t1000_system -{ - /* ROM drive */ - uint8_t *romdrive; - uint8_t rom_ctl; - uint32_t rom_offset; - mem_mapping_t rom_mapping; - - /* System control registers */ - uint8_t sys_ctl[16]; - uint8_t syskeys; - uint8_t turbo; - - /* NVRAM control */ - uint8_t nvr_c0; - uint8_t nvr_tick; - int nvr_addr; - uint8_t nvr_active; - - /* EMS data */ - uint8_t ems_reg[4]; - mem_mapping_t mapping[4]; - uint32_t page_exec[4]; - uint8_t ems_port_index; - uint16_t ems_port; - uint8_t is_640k; - uint32_t ems_base; - int32_t ems_pages; - - fdc_t *fdc; -} t1000; - -#define T1000_ROMSIZE (512 * 1024) /* Maximum ROM drive size is 512k */ - -/* The CONFIG.SYS storage (160 bytes) and battery-backed EMS (all RAM - * above 512k) are implemented as NVR devices */ - -void t1000_configsys_loadnvr() -{ - FILE *f; - - memset(config_sys, 0x1A, sizeof(config_sys)); - f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"rb"); - if (f) - { - fread(config_sys, sizeof(config_sys), 1, f); - fclose(f); - } -} - -/* All RAM beyond 512k is non-volatile */ -void t1000_emsboard_loadnvr() -{ - FILE *f; - - if (mem_size > 512) - { - f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb"); - if (f) - { - fread(&ram[512 * 1024], - 1024, (mem_size - 512), f); - fclose(f); - } - } -} - -void t1000_configsys_savenvr() -{ - FILE *f; - - f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"wb"); - if (f) - { - fwrite(config_sys, sizeof(config_sys), 1, f); - fclose(f); - } -} - - -void t1000_emsboard_savenvr() -{ - FILE *f; - - if (mem_size > 512) - { - f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb"); - if (f) - { - fwrite(&ram[512 * 1024], - 1024, (mem_size - 512), f); - fclose(f); - } - } -} - - - -/* Given an EMS page ID, return its physical address in RAM. */ -uint32_t ems_execaddr(struct t1000_system *sys, int pg, uint16_t val) -{ - if (!(val & 0x80)) return 0; /* Bit 7 reset => not mapped */ - if (!sys->ems_pages) return 0; /* No EMS available: all used by - * HardRAM or conventional RAM */ - - val &= 0x7F; - -/* pclog("Select EMS page: %d of %d\n", val, sys->ems_pages); */ - if (val < sys->ems_pages) - { -/* EMS is any memory above 512k, with ems_base giving the start address */ - return (512 * 1024) + (sys->ems_base * 0x10000) + (0x4000 * val); - } - return 0; -} - - -static uint8_t ems_in(uint16_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - -/* pclog("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]); */ - return sys->ems_reg[(addr >> 14) & 3]; -} - -static void ems_out(uint16_t addr, uint8_t val, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - int pg = (addr >> 14) & 3; - -/* pclog("ems_out(%04x, %02x) pg=%d\n", addr, val, pg); */ - sys->ems_reg[pg] = val; - sys->page_exec[pg] = ems_execaddr(sys, pg, val); - if (sys->page_exec[pg]) /* Page present */ - { - mem_mapping_enable(&sys->mapping[pg]); - mem_mapping_set_exec(&sys->mapping[pg], ram + sys->page_exec[pg]); - } - else - { - mem_mapping_disable(&sys->mapping[pg]); - } -} - - -/* Hardram size is in 64k units */ -static void ems_set_hardram(struct t1000_system *sys, uint8_t val) -{ - int n; - - val &= 0x1F; /* Mask off pageframe address */ - if (val && mem_size > 512) - { - sys->ems_base = val; - } - else - { - sys->ems_base = 0; - } -/* pclog("EMS base set to %02x\n", val); */ - sys->ems_pages = 48 - 4 * sys->ems_base; - if (sys->ems_pages < 0) sys->ems_pages = 0; - /* Recalculate EMS mappings */ - for (n = 0; n < 4; n++) - { - ems_out(n << 14, sys->ems_reg[n], sys); - } -} - - -static void ems_set_640k(struct t1000_system *sys, uint8_t val) -{ - if (val && mem_size >= 640) - { - mem_mapping_set_addr(&ram_low_mapping, 0, 640 * 1024); - sys->is_640k = 1; - } - else - { - mem_mapping_set_addr(&ram_low_mapping, 0, 512 * 1024); - sys->is_640k = 0; - } -} - -static void ems_set_port(struct t1000_system *sys, uint8_t val) -{ - int n; - -/* pclog("ems_set_port(%d)", val & 0x0F); */ - if (sys->ems_port) - { - for (n = 0; n <= 0xC000; n += 0x4000) - { - io_removehandler(sys->ems_port + n, 0x01, - ems_in, NULL, NULL, ems_out, NULL, NULL, sys); - } - sys->ems_port = 0; - } - val &= 0x0F; - sys->ems_port_index = val; - if (val == 7) /* No EMS */ - { - sys->ems_port = 0; - } - else - { - sys->ems_port = 0x208 | (val << 4); - for (n = 0; n <= 0xC000; n += 0x4000) - { - io_sethandler(sys->ems_port + n, 0x01, - ems_in, NULL, NULL, ems_out, NULL, NULL, sys); - } - sys->ems_port = 0; - } -/* pclog(" -> %04x\n", sys->ems_port); */ -} - -static int addr_to_page(uint32_t addr) -{ - return (addr - 0xD0000) / 0x4000; -} - -/* Read RAM in the EMS page frame */ -static uint8_t ems_read_ram(uint32_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return 0xFF; - addr = sys->page_exec[pg] + (addr & 0x3FFF); - return ram[addr]; -} - - - - -static uint16_t ems_read_ramw(uint32_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return 0xFF; - /* pclog("ems_read_ramw addr=%05x ", addr); */ - addr = sys->page_exec[pg] + (addr & 0x3FFF); - /* pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); */ - return *(uint16_t *)&ram[addr]; -} - - -static uint32_t ems_read_raml(uint32_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return 0xFF; - addr = sys->page_exec[pg] + (addr & 0x3FFF); - return *(uint32_t *)&ram[addr]; -} - -/* Write RAM in the EMS page frame */ -static void ems_write_ram(uint32_t addr, uint8_t val, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return; - addr = sys->page_exec[pg] + (addr & 0x3FFF); - if (ram[addr] != val) nvr_dosave = 1; - ram[addr] = val; -} - - -static void ems_write_ramw(uint32_t addr, uint16_t val, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return; - /* pclog("ems_write_ramw addr=%05x ", addr); */ - addr = sys->page_exec[pg] + (addr & 0x3FFF); - /* pclog("-> %06x val=%04x\n", addr, val); */ - - if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; - *(uint16_t *)&ram[addr] = val; -} - - -static void ems_write_raml(uint32_t addr, uint32_t val, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return; - addr = sys->page_exec[pg] + (addr & 0x3FFF); - if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; - *(uint32_t *)&ram[addr] = val; -} - - - - - -void t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask) -{ - t1000.syskeys &= ~andmask; - t1000.syskeys |= ormask; - t1000.syskeys ^= xormask; -} - - - -static uint8_t read_t1000_ctl(uint16_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - - switch (addr & 0x0F) - { - case 1: return sys->syskeys; -/* Detect EMS board */ - case 0x0F: switch (sys->sys_ctl[0x0E]) - { - case 0x50: if (mem_size <= 512) - return 0xFF; - return 0x90 | sys->ems_port_index; -/* 0x60 is the page frame address: (0xD000 - 0xC400) / 0x20 */ - case 0x51: return sys->ems_base | 0x60; - case 0x52: return sys->is_640k ? 0x80 : 0; - } - return 0xFF; - default: return sys->sys_ctl[addr & 0x0F]; - } -} - -static void t1200_turbo_set(uint8_t value) -{ - if (value == t1000.turbo) - { - return; - } - t1000.turbo = value; - if (!value) - { - cpu_dynamic_switch(0); - } - else - { - cpu_dynamic_switch(cpu); - } -} - -static void write_t1000_ctl(uint16_t addr, uint8_t val, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - - sys->sys_ctl[addr & 0x0F] = val; - switch (addr & 0x0F) - { - /* Video control */ - case 4: if (sys->sys_ctl[3] == 0x5A) - { - t1000_video_options_set((val & 0x20) ? 1 : 0); - t1000_display_set((val & 0x40) ? 0 : 1); - if (romset == ROM_T1200) - { - t1200_turbo_set((val & 0x80) ? 1 : 0); - } - } - break; - /* EMS control*/ - case 0x0F: - switch (sys->sys_ctl[0x0E]) - { - case 0x50: ems_set_port(sys, val); break; - case 0x51: ems_set_hardram(sys, val); break; - case 0x52: ems_set_640k(sys, val); break; - } - break; - - } -} - -/* Ports 0xC0 to 0xC3 appear to have two purposes: - * - * > Access to the 160 bytes of non-volatile RAM containing CONFIG.SYS - * > Reading the floppy changeline. I don't know why the Toshiba doesn't - * use the normal port 0x3F7 for this, but it doesn't. - * - */ -static uint8_t read_t1000_nvram(uint16_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - uint8_t tmp; - - switch (addr) - { - case 0xC2: /* Read next byte from NVRAM */ - tmp = 0xFF; - if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) - tmp = config_sys[sys->nvr_addr]; - ++sys->nvr_addr; - return tmp; - - case 0xC3: /* Read floppy changeline and NVRAM ready state */ - tmp = fdc_read(0x3F7, t1000.fdc); - - tmp = (tmp & 0x80) >> 3; /* Bit 4 is changeline */ - tmp |= (sys->nvr_active & 0xC0);/* Bits 6,7 are r/w mode */ - tmp |= 0x2E; /* Bits 5,3,2,1 always 1 */ - tmp |= (sys->nvr_active & 0x40) >> 6; /* Ready state */ - return tmp; - } - return 0xFF; -} - -static void write_t1000_nvram(uint16_t addr, uint8_t val, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - - switch (addr) - { -/* On the real T1000, port 0xC1 is only usable as the high byte of a 16-bit - * write to port 0xC0, with 0x5A in the low byte. */ - case 0xC0: sys->nvr_c0 = val; - break; -/* Write next byte to NVRAM */ - case 0xC1: if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) - { - if (config_sys[sys->nvr_addr] != val) - nvr_dosave = 1; - config_sys[sys->nvr_addr] = val; - } - ++sys->nvr_addr; - break; - case 0xC2: break; -/* At start of NVRAM read / write, 0x80 is written to port 0xC3. This seems - * to reset the NVRAM address counter. A single byte is then written (0xFF - * for write, 0x00 for read) which appears to be ignored. Simulate that by - * starting the address counter off at -1 */ - case 0xC3: sys->nvr_active = val; - if (val == 0x80) sys->nvr_addr = -1; - break; - } -} - -/* Port 0xC8 controls the ROM drive */ -static uint8_t read_t1000_rom_ctl(uint16_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - - return sys->rom_ctl; -} - -static void write_t1000_rom_ctl(uint16_t addr, uint8_t val, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - - sys->rom_ctl = val; - if (sys->romdrive && (val & 0x80)) /* Enable */ - { - sys->rom_offset = ((val & 0x7F) * 0x10000) % T1000_ROMSIZE; - mem_mapping_set_addr(&sys->rom_mapping, 0xA0000, 0x10000); - mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + - sys->rom_offset); - mem_mapping_enable(&sys->rom_mapping); - } - else - { - mem_mapping_disable(&sys->rom_mapping); - } -} - - -/* Read the ROM drive */ -static uint8_t t1000_read_rom(uint32_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - - if (!sys->romdrive) return 0xFF; - return sys->romdrive[sys->rom_offset + (addr & 0xFFFF)]; -} - -static uint16_t t1000_read_romw(uint32_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - - if (!sys->romdrive) return 0xFFFF; - return *(uint16_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xFFFF)]); -} - - -static uint32_t t1000_read_roml(uint32_t addr, void *priv) -{ - struct t1000_system *sys = (struct t1000_system *)priv; - - if (!sys->romdrive) return 0xFFFFFFFF; - return *(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xFFFF)]); -} - - -device_t * -t1000_get_device(void) -{ - return &t1000_device; -} - - -void machine_xt_t1000_init(machine_t *model) -{ - FILE *f; - int pg; - - memset(&t1000, 0, sizeof(t1000)); - t1000.turbo = 0xff; - t1000.ems_port_index = 7; /* EMS disabled */ -/* The ROM drive is optional. If the file is missing, continue to boot; the - * BIOS will complain 'No ROM drive' but boot normally from floppy. */ - - f = rom_fopen(L"roms/machines/t1000/t1000dos.rom", L"rb"); - if (f) - { - t1000.romdrive = malloc(T1000_ROMSIZE); - if (t1000.romdrive) - { - memset(t1000.romdrive, 0xFF, T1000_ROMSIZE); - fread(t1000.romdrive, T1000_ROMSIZE, 1, f); - } - fclose(f); - } - mem_mapping_add(&t1000.rom_mapping, 0xA0000, 0x10000, - t1000_read_rom, t1000_read_romw, t1000_read_roml, - NULL, NULL, NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); - mem_mapping_disable(&t1000.rom_mapping); - - /* Map the EMS page frame */ - for (pg = 0; pg < 4; pg++) - { - mem_mapping_add(&t1000.mapping[pg], - 0xD0000 + (0x4000 * pg), 16384, - ems_read_ram, ems_read_ramw, ems_read_raml, - ems_write_ram, ems_write_ramw, ems_write_raml, - NULL, MEM_MAPPING_EXTERNAL, - &t1000); - /* Start them all off disabled */ - mem_mapping_disable(&t1000.mapping[pg]); - } - - /* Non-volatile RAM for CONFIG.SYS */ - io_sethandler(0xC0, 4, read_t1000_nvram, NULL, NULL, - write_t1000_nvram, NULL, NULL, &t1000); - /* ROM drive */ - io_sethandler(0xC8, 1, read_t1000_rom_ctl, NULL, NULL, - write_t1000_rom_ctl, NULL, NULL, &t1000); - /* System control functions, and add-on memory board */ - io_sethandler(0xE0, 0x10, read_t1000_ctl, NULL, NULL, - write_t1000_ctl, NULL, NULL, &t1000); - - machine_common_init(model); - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); - device_add(&keyboard_xt_device); - t1000.fdc = device_add(&fdc_xt_device); - nmi_init(); - nvr_tc8521_init(); -/* No gameport, and no provision to fit one device_add(&gameport_device); */ - - device_add(&t1000_device); -} - - -device_t * -t1200_get_device(void) -{ - return &t1200_device; -} - - -void machine_xt_t1200_init(machine_t *model) -{ - int pg; - - memset(&t1000, 0, sizeof(t1000)); - t1000.ems_port_index = 7; /* EMS disabled */ - - mem_mapping_add(&t1000.rom_mapping, 0xA0000, 0x10000, - t1000_read_rom, t1000_read_romw, t1000_read_roml, - NULL, NULL, NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); - mem_mapping_disable(&t1000.rom_mapping); - - /* Map the EMS page frame */ - for (pg = 0; pg < 4; pg++) - { - mem_mapping_add(&t1000.mapping[pg], - 0xD0000 + (0x4000 * pg), 16384, - ems_read_ram, ems_read_ramw, ems_read_raml, - ems_write_ram, ems_write_ramw, ems_write_raml, - NULL, MEM_MAPPING_EXTERNAL, - &t1000); - /* Start them all off disabled */ - mem_mapping_disable(&t1000.mapping[pg]); - } - - /* System control functions, and add-on memory board */ - io_sethandler(0xE0, 0x10, read_t1000_ctl, NULL, NULL, - write_t1000_ctl, NULL, NULL, &t1000); - - machine_common_init(model); - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); - device_add(&keyboard_xt_device); - t1000.fdc = device_add(&fdc_xt_device); - nmi_init(); - nvr_tc8521_init(); -/* No gameport, and no provision to fit one device_add(&gameport_device); */ - - device_add(&t1200_device); -} +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Toshiba T1000 and T1200 portables. + * + * The T1000 is the T3100e's little brother -- a real laptop + * with a rechargeable battery. + * + * Features: 80C88 at 4.77MHz + * - 512k system RAM + * - 640x200 monochrome LCD + * - 82-key keyboard + * - Real-time clock. Not the normal 146818, but a TC8521, + * which is a 4-bit chip. + * - A ROM drive (128k, 256k or 512k) which acts as a mini + * hard drive and contains a copy of DOS 2.11. + * - 160 bytes of non-volatile RAM for the CONFIG.SYS used + * when booting from the ROM drive. Possibly physically + * located in the keyboard controller RAM. + * + * An optional memory expansion board can be fitted. This adds + * 768k of RAM, which can be used for up to three purposes: + * > Conventional memory -- 128k between 512k and 640k + * > HardRAM -- a battery-backed RAM drive. + * > EMS + * + * This means that there are up to three different + * implementations of non-volatile RAM in the same computer + * (52 nibbles in the TC8521, 160 bytes of CONFIG.SYS, and + * up to 768k of HardRAM). + * + * The T1200 is a slightly upgraded version with a turbo mode + * (double CPU clock, 9.54MHz) and an optional hard drive. + * The interface for this is proprietary both at the physical + * and programming level. + * + * 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb] + * or 0Dh [10Mb]. + * + * The hard drive is a 20MB (615/2/26) RLL 3.5" drive. + * + * The TC8521 is a 4-bit RTC, so each memory location can only + * hold a single BCD digit. Hence everything has 'ones' and + * 'tens' digits. + * + * NOTE: Still need to figure out a way to load/save ConfigSys and + * HardRAM stuff. Needs to be linked in to the NVR code. + * + * Version: @(#)m_xt_t1000.c 1.0.2 2018/03/11 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Miran Grca. + * Copyright 2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../nmi.h" +#include "../mem.h" +#include "../rom.h" +#include "../nvr.h" +#include "../device.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../video/video.h" +#include "../plat.h" +#include "machine.h" +#include "m_xt_t1000.h" + + +#define T1000_ROMSIZE (512*1024UL) /* Maximum ROM drive size is 512k */ + + +enum TC8521_ADDR { + /* Page 0 registers */ + TC8521_SECOND1 = 0, + TC8521_SECOND10, + TC8521_MINUTE1, + TC8521_MINUTE10, + TC8521_HOUR1, + TC8521_HOUR10, + TC8521_WEEKDAY, + TC8521_DAY1, + TC8521_DAY10, + TC8521_MONTH1, + TC8521_MONTH10, + TC8521_YEAR1, + TC8521_YEAR10, + TC8521_PAGE, /* PAGE register */ + TC8521_TEST, /* TEST register */ + TC8521_RESET, /* RESET register */ + + /* Page 1 registers */ + TC8521_24HR = 0x1A, + TC8521_LEAPYEAR = 0x1B +}; + + +typedef struct { + /* ROM drive */ + uint8_t *romdrive; + uint8_t rom_ctl; + uint32_t rom_offset; + mem_mapping_t rom_mapping; + + /* CONFIG.SYS drive. */ + uint8_t config[160]; + + /* System control registers */ + uint8_t sys_ctl[16]; + uint8_t syskeys; + uint8_t turbo; + + /* NVRAM control */ + uint8_t nvr_c0; + uint8_t nvr_tick; + int nvr_addr; + uint8_t nvr_active; + + /* EMS data */ + uint8_t ems_reg[4]; + mem_mapping_t mapping[4]; + uint32_t page_exec[4]; + uint8_t ems_port_index; + uint16_t ems_port; + uint8_t is_640k; + uint32_t ems_base; + int32_t ems_pages; + + fdc_t *fdc; + + nvr_t nvr; +} t1000_t; + + +static t1000_t t1000; + + +/* Set the chip time. */ +static void +tc8521_time_set(uint8_t *regs, struct tm *tm) +{ + regs[TC8521_SECOND1] = (tm->tm_sec % 10); + regs[TC8521_SECOND10] = (tm->tm_sec / 10); + regs[TC8521_MINUTE1] = (tm->tm_min % 10); + regs[TC8521_MINUTE10] = (tm->tm_min / 10); + if (regs[TC8521_24HR] & 0x01) { + regs[TC8521_HOUR1] = (tm->tm_hour % 10); + regs[TC8521_HOUR10] = (tm->tm_hour / 10); + } else { + regs[TC8521_HOUR1] = ((tm->tm_hour % 12) % 10); + regs[TC8521_HOUR10] = (((tm->tm_hour % 12) / 10) | + ((tm->tm_hour >= 12) ? 2 : 0)); + } + regs[TC8521_WEEKDAY] = tm->tm_wday; + regs[TC8521_DAY1] = (tm->tm_mday % 10); + regs[TC8521_DAY10] = (tm->tm_mday / 10); + regs[TC8521_MONTH1] = ((tm->tm_mon + 1) % 10); + regs[TC8521_MONTH10] = ((tm->tm_mon + 1) / 10); + regs[TC8521_YEAR1] = ((tm->tm_year - 80) % 10); + regs[TC8521_YEAR10] = (((tm->tm_year - 80) % 100) / 10); +} + + +/* Get the chip time. */ +#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)]) +static void +tc8521_time_get(uint8_t *regs, struct tm *tm) +{ + tm->tm_sec = nibbles(TC8521_SECOND); + tm->tm_min = nibbles(TC8521_MINUTE); + if (regs[TC8521_24HR] & 0x01) + tm->tm_hour = nibbles(TC8521_HOUR); + else + tm->tm_hour = ((nibbles(TC8521_HOUR) % 12) + + (regs[TC8521_HOUR10] & 0x02) ? 12 : 0); +//FIXME: wday + tm->tm_mday = nibbles(TC8521_DAY); + tm->tm_mon = (nibbles(TC8521_MONTH) - 1); + tm->tm_year = (nibbles(TC8521_YEAR) + 1980); +} + + +/* This is called every second through the NVR/RTC hook. */ +static void +tc8521_tick(nvr_t *nvr) +{ + pclog("TC8521: ping\n"); +} + + +static void +tc8521_start(nvr_t *nvr) +{ + struct tm tm; + + /* Initialize the internal and chip times. */ + if (enable_sync) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + tc8521_time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + tc8521_time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } + +#if 0 + /* Start the RTC - BIOS will do this. */ + nvr->regs[TC8521_PAGE] |= 0x80; +#endif +} + + +/* Write to one of the chip registers. */ +static void +tc8521_write(uint16_t addr, uint8_t val, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t page; + + /* Get to the correct register page. */ + addr &= 0x0f; + page = nvr->regs[0x0d] & 0x03; + if (addr < 0x0d) + addr += (16 * page); + + if (addr >= 0x10 && nvr->regs[addr] != val) + nvr_dosave = 1; + + /* Store the new value. */ + nvr->regs[addr] = val; +} + + +/* Read from one of the chip registers. */ +static uint8_t +tc8521_read(uint16_t addr, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t page; + + /* Get to the correct register page. */ + addr &= 0x0f; + page = nvr->regs[0x0d] & 0x03; + if (addr < 0x0d) + addr += (16 * page); + + /* Grab and return the desired value. */ + return(nvr->regs[addr]); +} + + +/* Reset the 8521 to a default state. */ +static void +tc8521_reset(nvr_t *nvr) +{ + /* Clear the NVRAM. */ + memset(nvr->regs, 0xff, nvr->size); + + /* Reset the RTC registers. */ + memset(nvr->regs, 0x00, 16); + nvr->regs[TC8521_WEEKDAY] = 0x01; + nvr->regs[TC8521_DAY1] = 0x01; + nvr->regs[TC8521_MONTH1] = 0x01; +} + + +static void +tc8521_init(nvr_t *nvr, int size) +{ + /* This is machine specific. */ + nvr->size = size; + nvr->irq = -1; + + /* Set up any local handlers here. */ + nvr->reset = tc8521_reset; + nvr->start = tc8521_start; + nvr->tick = tc8521_tick; + + /* Initialize the actual NVR. */ + nvr_init(nvr); + + io_sethandler(0x02c0, 16, + tc8521_read,NULL,NULL, tc8521_write,NULL,NULL, nvr); +} + + +/* Given an EMS page ID, return its physical address in RAM. */ +static uint32_t +ems_execaddr(t1000_t *sys, int pg, uint16_t val) +{ + if (!(val & 0x80)) return(0); /* Bit 7 reset => not mapped */ + if (!sys->ems_pages) return(0); /* No EMS available: all used by + * HardRAM or conventional RAM */ + val &= 0x7f; + +#if 0 + pclog("Select EMS page: %d of %d\n", val, sys->ems_pages); +#endif + if (val < sys->ems_pages) { + /* EMS is any memory above 512k, + with ems_base giving the start address */ + return((512 * 1024) + (sys->ems_base * 0x10000) + (0x4000 * val)); + } + + return(0); +} + + +static uint8_t +ems_in(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + +#if 0 + pclog("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]); +#endif + return(sys->ems_reg[(addr >> 14) & 3]); +} + + +static void +ems_out(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = (addr >> 14) & 3; + +#if 0 + pclog("ems_out(%04x, %02x) pg=%d\n", addr, val, pg); +#endif + sys->ems_reg[pg] = val; + sys->page_exec[pg] = ems_execaddr(sys, pg, val); + if (sys->page_exec[pg]) { + /* Page present */ + mem_mapping_enable(&sys->mapping[pg]); + mem_mapping_set_exec(&sys->mapping[pg], ram + sys->page_exec[pg]); + } else { + mem_mapping_disable(&sys->mapping[pg]); + } +} + + +/* Hardram size is in 64k units */ +static void +ems_set_hardram(t1000_t *sys, uint8_t val) +{ + int n; + + val &= 0x1f; /* Mask off pageframe address */ + if (val && mem_size > 512) + sys->ems_base = val; + else + sys->ems_base = 0; + +#if 0 + pclog("EMS base set to %02x\n", val); +#endif + sys->ems_pages = 48 - 4 * sys->ems_base; + if (sys->ems_pages < 0) sys->ems_pages = 0; + + /* Recalculate EMS mappings */ + for (n = 0; n < 4; n++) + ems_out(n << 14, sys->ems_reg[n], sys); +} + + +static void +ems_set_640k(t1000_t *sys, uint8_t val) +{ + if (val && mem_size >= 640) { + mem_mapping_set_addr(&ram_low_mapping, 0, 640 * 1024); + sys->is_640k = 1; + } else { + mem_mapping_set_addr(&ram_low_mapping, 0, 512 * 1024); + sys->is_640k = 0; + } +} + + +static void +ems_set_port(t1000_t *sys, uint8_t val) +{ + int n; + +#if 0 + pclog("ems_set_port(%d)", val & 0x0f); +#endif + if (sys->ems_port) { + for (n = 0; n <= 0xc000; n += 0x4000) { + io_removehandler(sys->ems_port+n, 1, + ems_in,NULL,NULL, ems_out,NULL,NULL, sys); + } + sys->ems_port = 0; + } + + val &= 0x0f; + sys->ems_port_index = val; + if (val == 7) { + /* No EMS */ + sys->ems_port = 0; + } else { + sys->ems_port = 0x208 | (val << 4); + for (n = 0; n <= 0xc000; n += 0x4000) { + io_sethandler(sys->ems_port+n, 1, + ems_in,NULL,NULL, ems_out,NULL,NULL, sys); + } + sys->ems_port = 0; + } + +#if 0 + pclog(" -> %04x\n", sys->ems_port); +#endif +} + + +static int +addr_to_page(uint32_t addr) +{ + return((addr - 0xd0000) / 0x4000); +} + + +/* Read RAM in the EMS page frame. */ +static uint8_t +ems_read_ram(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + addr = sys->page_exec[pg] + (addr & 0x3fff); + + return(ram[addr]); +} + + +static uint16_t +ems_read_ramw(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + +#if 0 + pclog("ems_read_ramw addr=%05x ", addr); +#endif + addr = sys->page_exec[pg] + (addr & 0x3FFF); + +#if 0 + pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); +#endif + + return(*(uint16_t *)&ram[addr]); +} + + +static uint32_t +ems_read_raml(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + addr = sys->page_exec[pg] + (addr & 0x3fff); + + return(*(uint32_t *)&ram[addr]); +} + + +/* Write RAM in the EMS page frame. */ +static void +ems_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + + addr = sys->page_exec[pg] + (addr & 0x3fff); + if (ram[addr] != val) nvr_dosave = 1; + + ram[addr] = val; +} + + +static void +ems_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + +#if 0 + pclog("ems_write_ramw addr=%05x ", addr); +#endif + addr = sys->page_exec[pg] + (addr & 0x3fff); + +#if 0 + pclog("-> %06x val=%04x\n", addr, val); +#endif + + if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; + + *(uint16_t *)&ram[addr] = val; +} + + +static void +ems_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + + addr = sys->page_exec[pg] + (addr & 0x3fff); + if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; + + *(uint32_t *)&ram[addr] = val; +} + + +static uint8_t +read_ctl(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + uint8_t ret = 0xff; + + switch (addr & 0x0f) { + case 1: + ret = sys->syskeys; + break; + + case 0x0f: /* Detect EMS board */ + switch (sys->sys_ctl[0x0e]) { + case 0x50: + if (mem_size > 512) break; + ret = (0x90 | sys->ems_port_index); + break; + + case 0x51: + /* 0x60 is the page frame address: + (0xd000 - 0xc400) / 0x20 */ + ret = (sys->ems_base | 0x60); + break; + + case 0x52: + ret = (sys->is_640k ? 0x80 : 0); + break; + } + break; + + default: + ret = (sys->sys_ctl[addr & 0x0f]); + } + + return(ret); +} + + +static void +t1200_turbo_set(uint8_t value) +{ + if (value == t1000.turbo) return; + + t1000.turbo = value; + if (! value) + cpu_dynamic_switch(0); + else + cpu_dynamic_switch(cpu); +} + + +static void +write_ctl(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + sys->sys_ctl[addr & 0x0f] = val; + switch (addr & 0x0f) { + case 4: /* Video control */ + if (sys->sys_ctl[3] == 0x5A) { + t1000_video_options_set((val & 0x20) ? 1 : 0); + t1000_display_set((val & 0x40) ? 0 : 1); + if (romset == ROM_T1200) + t1200_turbo_set((val & 0x80) ? 1 : 0); + } + break; + + case 0x0f: /* EMS control */ + switch (sys->sys_ctl[0x0e]) { + case 0x50: + ems_set_port(sys, val); + break; + + case 0x51: + ems_set_hardram(sys, val); + break; + + case 0x52: + ems_set_640k(sys, val); + break; + } + break; + } +} + + +/* Ports 0xC0 to 0xC3 appear to have two purposes: + * + * > Access to the 160 bytes of non-volatile RAM containing CONFIG.SYS + * > Reading the floppy changeline. I don't know why the Toshiba doesn't + * use the normal port 0x3F7 for this, but it doesn't. + * + */ +static uint8_t +t1000_read_nvram(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + uint8_t tmp = 0xff; + + switch (addr) { + case 0xc2: /* Read next byte from NVRAM */ + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) + tmp = sys->config[sys->nvr_addr]; + sys->nvr_addr++; + break; + + case 0xc3: /* Read floppy changeline and NVRAM ready state */ + tmp = fdc_read(0x03f7, t1000.fdc); + + tmp = (tmp & 0x80) >> 3; /* Bit 4 is changeline */ + tmp |= (sys->nvr_active & 0xc0);/* Bits 6,7 are r/w mode */ + tmp |= 0x2e; /* Bits 5,3,2,1 always 1 */ + tmp |= (sys->nvr_active & 0x40) >> 6; /* Ready state */ + break; + } + + return(tmp); +} + + +static void +t1000_write_nvram(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + /* + * On the real T1000, port 0xC1 is only usable as the high byte + * of a 16-bit write to port 0xC0, with 0x5A in the low byte. + */ + switch (addr) { + case 0xc0: + sys->nvr_c0 = val; + break; + + case 0xc1: /* Write next byte to NVRAM */ + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) { + if (sys->config[sys->nvr_addr] != val) + nvr_dosave = 1; + sys->config[sys->nvr_addr] = val; + } + sys->nvr_addr++; + break; + + case 0xc2: + break; + + case 0xc3: + /* + * At start of NVRAM read / write, 0x80 is written to + * port 0xC3. This seems to reset the NVRAM address + * counter. A single byte is then written (0xff for + * write, 0x00 for read) which appears to be ignored. + * Simulate that by starting the address counter off + * at -1. + */ + sys->nvr_active = val; + if (val == 0x80) sys->nvr_addr = -1; + break; + } +} + + +/* Port 0xC8 controls the ROM drive */ +static uint8_t +t1000_read_rom_ctl(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + return(sys->rom_ctl); +} + + +static void +t1000_write_rom_ctl(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + sys->rom_ctl = val; + if (sys->romdrive && (val & 0x80)) { + /* Enable */ + sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMSIZE; + mem_mapping_set_addr(&sys->rom_mapping, 0xa0000, 0x10000); + mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + sys->rom_offset); + mem_mapping_enable(&sys->rom_mapping); + } else { + mem_mapping_disable(&sys->rom_mapping); + } +} + + +/* Read the ROM drive */ +static uint8_t +t1000_read_rom(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xff); + + return(sys->romdrive[sys->rom_offset + (addr & 0xffff)]); +} + + +static uint16_t +t1000_read_romw(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xffff); + + return(*(uint16_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); +} + + +static uint32_t +t1000_read_roml(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xffffffff); + + return(*(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); +} + + +device_t * +t1000_get_device(void) +{ + return(&t1000_video_device); +} + + +void +machine_xt_t1000_init(machine_t *model) +{ + FILE *f; + int pg; + + memset(&t1000, 0x00, sizeof(t1000)); + t1000.turbo = 0xff; + t1000.ems_port_index = 7; /* EMS disabled */ + + /* Load the T1000 CGA Font ROM. */ + loadfont(L"roms/machines/t1000/t1000font.rom", 2); + + /* + * The ROM drive is optional. + * + * If the file is missing, continue to boot; the BIOS will + * complain 'No ROM drive' but boot normally from floppy. + */ + f = rom_fopen(L"roms/machines/t1000/t1000dos.rom", L"rb"); + if (f != NULL) { + t1000.romdrive = malloc(T1000_ROMSIZE); + if (t1000.romdrive) { + memset(t1000.romdrive, 0xff, T1000_ROMSIZE); + fread(t1000.romdrive, T1000_ROMSIZE, 1, f); + } + fclose(f); + } + mem_mapping_add(&t1000.rom_mapping, 0xa0000, 0x10000, + t1000_read_rom,t1000_read_romw,t1000_read_roml, + NULL,NULL,NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); + mem_mapping_disable(&t1000.rom_mapping); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { + mem_mapping_add(&t1000.mapping[pg], 0xd0000 + (0x4000 * pg), 16384, + ems_read_ram,ems_read_ramw,ems_read_raml, + ems_write_ram,ems_write_ramw,ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, &t1000); + + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* Non-volatile RAM for CONFIG.SYS */ + io_sethandler(0xc0, 4, + t1000_read_nvram,NULL,NULL, + t1000_write_nvram,NULL,NULL, &t1000); + + /* ROM drive */ + io_sethandler(0xc8, 1, + t1000_read_rom_ctl,NULL,NULL, + t1000_write_rom_ctl,NULL,NULL, &t1000); + + /* System control functions, and add-on memory board */ + io_sethandler(0xe0, 16, + read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); + + machine_common_init(model); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_device); + t1000.fdc = device_add(&fdc_xt_device); + nmi_init(); + + tc8521_init(&t1000.nvr, model->nvrmask + 1); + + device_add(&t1000_video_device); +} + + +device_t * +t1200_get_device(void) +{ + return(&t1200_video_device); +} + + +void +machine_xt_t1200_init(machine_t *model) +{ + int pg; + + memset(&t1000, 0x00, sizeof(t1000)); + t1000.ems_port_index = 7; /* EMS disabled */ + + /* Load the T1200 CGA Font ROM. */ + loadfont(L"roms/machines/t1200/t1000font.bin", 2); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { + mem_mapping_add(&t1000.mapping[pg], + 0xd0000 + (0x4000 * pg), 16384, + ems_read_ram,ems_read_ramw,ems_read_raml, + ems_write_ram,ems_write_ramw,ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, &t1000); + + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* System control functions, and add-on memory board */ + io_sethandler(0xe0, 16, + read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); + + machine_common_init(model); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_device); + t1000.fdc = device_add(&fdc_xt_device); + nmi_init(); + + tc8521_init(&t1000.nvr, model->nvrmask + 1); + + device_add(&t1200_video_device); +} + + +void +t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask) +{ + t1000.syskeys &= ~andmask; + t1000.syskeys |= ormask; + t1000.syskeys ^= xormask; +} + + +#if 0 +void +t1000_configsys_load(void) +{ + FILE *f; + + memset(config_sys, 0x1a, sizeof(config_sys)); + f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"rb"); + if (f != NULL) { + fread(config_sys, sizeof(config_sys), 1, f); + fclose(f); + } +} + + +void +t1000_configsys_save(void) +{ + FILE *f; + + f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"wb"); + if (f != NULL) { + fwrite(config_sys, sizeof(config_sys), 1, f); + fclose(f); + } +} + + +/* All RAM beyond 512k is non-volatile */ +void +t1000_emsboard_load(void) +{ + FILE *f; + + if (mem_size > 512) { + f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb"); + if (f != NULL) { + fread(&ram[512 * 1024], 1024, (mem_size - 512), f); + fclose(f); + } + } +} + + +void +t1000_emsboard_save(void) +{ + FILE *f; + + if (mem_size > 512) { + f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb"); + if (f != NULL) { + fwrite(&ram[512 * 1024], 1024, (mem_size - 512), f); + fclose(f); + } + } +} +#endif diff --git a/src/machine/m_xt_t1000.h b/src/machine/m_xt_t1000.h index 7c3e26f47..545861eb5 100644 --- a/src/machine/m_xt_t1000.h +++ b/src/machine/m_xt_t1000.h @@ -1,7 +1,59 @@ -void t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask); +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the Toshiba T1000/T1200 machines. + * + * Version: @(#)m_xt_t1000.h 1.0.2 2018/03/10 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef MACHINE_T1000_H +# define MACHINE_T1000_H -void t1000_configsys_loadnvr(); -void t1000_emsboard_loadnvr(); -void t1000_configsys_savenvr(); -void t1000_emsboard_savenvr(); +extern device_t t1000_video_device; +extern device_t t1200_video_device; + + +extern void t1000_video_options_set(uint8_t options); +extern void t1000_display_set(uint8_t internal); + +extern void t1000_syskey(uint8_t amask, uint8_t omask, uint8_t xmask); + +extern void t1000_configsys_load(void); +extern void t1000_configsys_save(void); + +extern void t1000_emsboard_load(void); +extern void t1000_emsboard_save(void); + + +#endif /*MACHINE_T1000_H*/ diff --git a/src/machine/m_xt_t1000_vid.c b/src/machine/m_xt_t1000_vid.c new file mode 100644 index 000000000..e2058c94f --- /dev/null +++ b/src/machine/m_xt_t1000_vid.c @@ -0,0 +1,753 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Toshiba T1000 plasma display, which + * has a fixed resolution of 640x200 pixels. + * + * Version: @(#)m_xt_t1000_vid.c 1.0.4 2018/03/10 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Miran Grca. + * Copyright 2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../timer.h" +#include "../cpu/cpu.h" +#include "../video/video.h" +#include "../video/vid_cga.h" +#include "m_xt_t1000.h" + + +#define T1000_XSIZE 640 +#define T1000_YSIZE 200 + + +/* Mapping of attributes to colours */ +static uint32_t blue, grey; +static uint8_t boldcols[256]; /* Which attributes use the bold font */ +static uint32_t blinkcols[256][2]; +static uint32_t normcols[256][2]; +static uint8_t language; + + +/* Video options set by the motherboard; they will be picked up by the card + * on the next poll. + * + * Bit 1: Danish + * Bit 0: Thin font + */ +static uint8_t st_video_options; +static int8_t st_display_internal = -1; + +void t1000_video_options_set(uint8_t options) +{ + st_video_options = options & 1; + st_video_options |= language; +} + +void t1000_display_set(uint8_t internal) +{ + st_display_internal = (int8_t)internal; +} + +uint8_t t1000_display_get() +{ + return (uint8_t)st_display_internal; +} + + +typedef struct t1000_t +{ + mem_mapping_t mapping; + + cga_t cga; /* The CGA is used for the external + * display; most of its registers are + * ignored by the plasma display. */ + + int font; /* Current font, 0-3 */ + int enabled; /* Hardware enabled, 0 or 1 */ + int internal; /* Using internal display? */ + uint8_t attrmap; /* Attribute mapping register */ + + int dispontime, dispofftime; + + int linepos, displine; + int vc; + int dispon; + int vsynctime; + uint8_t video_options; + + uint8_t *vram; +} t1000_t; + + +static void t1000_recalctimings(t1000_t *t1000); +static void t1000_write(uint32_t addr, uint8_t val, void *p); +static uint8_t t1000_read(uint32_t addr, void *p); +static void t1000_recalcattrs(t1000_t *t1000); + + +static void t1000_out(uint16_t addr, uint8_t val, void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + switch (addr) + { + /* Emulated CRTC, register select */ + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + cga_out(addr, val, &t1000->cga); + break; + + /* Emulated CRTC, value */ + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + /* Register 0x12 controls the attribute mappings for the + * LCD screen. */ + if (t1000->cga.crtcreg == 0x12) + { + t1000->attrmap = val; + t1000_recalcattrs(t1000); + return; + } + cga_out(addr, val, &t1000->cga); + + t1000_recalctimings(t1000); + return; + + /* CGA control register */ + case 0x3D8: + cga_out(addr, val, &t1000->cga); + return; + /* CGA colour register */ + case 0x3D9: + cga_out(addr, val, &t1000->cga); + return; + } +} + +static uint8_t t1000_in(uint16_t addr, void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + uint8_t val; + + switch (addr) + { + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + if (t1000->cga.crtcreg == 0x12) + { + val = t1000->attrmap & 0x0F; + if (t1000->internal) val |= 0x20; /* LCD / CRT */ + return val; + } + } + + return cga_in(addr, &t1000->cga); +} + + + + +static void t1000_write(uint32_t addr, uint8_t val, void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + egawrites++; + +// pclog("CGA_WRITE %04X %02X\n", addr, val); + t1000->vram[addr & 0x3fff] = val; + cycles -= 4; +} + +static uint8_t t1000_read(uint32_t addr, void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + egareads++; + cycles -= 4; + +// pclog("CGA_READ %04X\n", addr); + return t1000->vram[addr & 0x3fff]; +} + + + +static void t1000_recalctimings(t1000_t *t1000) +{ + double disptime; + double _dispontime, _dispofftime; + + if (!t1000->internal) + { + cga_recalctimings(&t1000->cga); + return; + } + disptime = 651; + _dispontime = 640; + _dispofftime = disptime - _dispontime; + t1000->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + t1000->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +/* Draw a row of text in 80-column mode */ +static void t1000_text_row80(t1000_t *t1000) +{ + uint32_t cols[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + 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; + + sc = (t1000->displine) & 7; + addr = ((ma & ~1) + (t1000->displine >> 3) * 80) * 2; + ma += (t1000->displine >> 3) * 80; + + if ((t1000->cga.crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) && + ((t1000->cga.crtc[11] & 0x0F) >= sc); + } + for (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)); + + blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (t1000->video_options & 1) + bold = boldcols[attr] ? chr : chr + 256; + else + bold = boldcols[attr] ? chr + 256 : chr; + if (t1000->video_options & 2) + bold += 512; + + if (t1000->cga.cgamode & 0x20) /* Blink */ + { + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; + } + else + { + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); + } + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + ++ma; + } +} + +/* Draw a row of text in 40-column mode */ +static void t1000_text_row40(t1000_t *t1000) +{ + uint32_t cols[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + 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; + + sc = (t1000->displine) & 7; + addr = ((ma & ~1) + (t1000->displine >> 3) * 40) * 2; + ma += (t1000->displine >> 3) * 40; + + if ((t1000->cga.crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) && + ((t1000->cga.crtc[11] & 0x0F) >= sc); + } + for (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)); + + blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (t1000->video_options & 1) + bold = boldcols[attr] ? chr : chr + 256; + else + bold = boldcols[attr] ? chr + 256 : chr; + if (t1000->video_options & 2) + bold += 512; + + if (t1000->cga.cgamode & 0x20) /* Blink */ + { + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; + } + else + { + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2 + 1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); + } + } + else + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2+1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + ++ma; + } +} + +/* Draw a line in CGA 640x200 mode */ +static void t1000_cgaline6(t1000_t *t1000) +{ + int x, c; + uint8_t dat; + uint32_t ink = 0; + uint16_t addr; + 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; + + addr = ((t1000->displine) & 1) * 0x2000 + + (t1000->displine >> 1) * 80 + + ((ma & ~1) << 1); + + for (x = 0; x < 80; x++) + { + dat = t1000->vram[addr & 0x3FFF]; + addr++; + + for (c = 0; c < 8; c++) + { + ink = (dat & 0x80) ? fg : bg; + if (!(t1000->cga.cgamode & 8)) + ink = grey; + ((uint32_t *)buffer32->line[t1000->displine])[x*8+c] = ink; + dat = dat << 1; + } + } +} + +/* Draw a line in CGA 320x200 mode. Here the CGA colours are converted to + * dither patterns: colour 1 to 25% grey, colour 2 to 50% grey */ +static void t1000_cgaline4(t1000_t *t1000) +{ + int x, c; + uint8_t dat, pattern; + uint32_t ink0, 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); + + for (x = 0; x < 80; x++) + { + dat = t1000->vram[addr & 0x3FFF]; + addr++; + + for (c = 0; c < 4; c++) + { + pattern = (dat & 0xC0) >> 6; + if (!(t1000->cga.cgamode & 8)) pattern = 0; + + switch (pattern & 3) + { + default: + case 0: ink0 = ink1 = grey; break; + case 1: if (t1000->displine & 1) + { + ink0 = grey; ink1 = grey; + } + else + { + ink0 = blue; ink1 = grey; + } + break; + case 2: if (t1000->displine & 1) + { + ink0 = grey; ink1 = blue; + } + else + { + ink0 = blue; ink1 = grey; + } + break; + case 3: ink0 = ink1 = blue; break; + + } + ((uint32_t *)buffer32->line[t1000->displine])[x*8+2*c] = ink0; + ((uint32_t *)buffer32->line[t1000->displine])[x*8+2*c+1] = ink1; + dat = dat << 2; + } + } +} + +static void t1000_poll(void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + + if (t1000->video_options != st_video_options) + { + t1000->video_options = st_video_options; + + /* Set the font used for the external display */ + t1000->cga.fontbase = ((t1000->video_options & 3) * 256); + } + /* Switch between internal plasma and external CRT display. */ + if (st_display_internal != -1 && st_display_internal != t1000->internal) + { + t1000->internal = st_display_internal; + t1000_recalctimings(t1000); + } + if (!t1000->internal) + { + cga_poll(&t1000->cga); + return; + } + + if (!t1000->linepos) + { + t1000->cga.vidtime += t1000->dispofftime; + t1000->cga.cgastat |= 1; + t1000->linepos = 1; + if (t1000->dispon) + { + if (t1000->displine == 0) + { + video_wait_for_buffer(); + } + + /* Graphics */ + if (t1000->cga.cgamode & 0x02) + { + if (t1000->cga.cgamode & 0x10) + t1000_cgaline6(t1000); + else t1000_cgaline4(t1000); + } + else + if (t1000->cga.cgamode & 0x01) /* High-res text */ + { + t1000_text_row80(t1000); + } + else + { + t1000_text_row40(t1000); + } + } + t1000->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (t1000->displine == 200) /* Start of VSYNC */ + { + t1000->cga.cgastat |= 8; + t1000->dispon = 0; + } + if (t1000->displine == 216) /* End of VSYNC */ + { + t1000->displine = 0; + t1000->cga.cgastat &= ~8; + t1000->dispon = 1; + } + } + else + { + if (t1000->dispon) + { + t1000->cga.cgastat &= ~1; + } + t1000->cga.vidtime += t1000->dispontime; + t1000->linepos = 0; + + if (t1000->displine == 200) + { + /* Hardcode 640x200 window size */ + if (T1000_XSIZE != xsize || T1000_YSIZE != ysize) + { + xsize = T1000_XSIZE; + ysize = T1000_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 640x200 resolution */ + video_res_x = T1000_XSIZE; + video_res_y = T1000_YSIZE; + + if (t1000->cga.cgamode & 0x02) + { + if (t1000->cga.cgamode & 0x10) + video_bpp = 1; + else video_bpp = 2; + + } + else video_bpp = 0; + t1000->cga.cgablink++; + } + } +} + +static void t1000_recalcattrs(t1000_t *t1000) +{ + 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 */ + blue = makecol(0x2D, 0x39, 0x5A); + grey = makecol(0x85, 0xa0, 0xD6); + + /* Initialise the attribute mapping. Start by defaulting everything + * to grey on blue, and with bold set by bit 3 */ + for (n = 0; n < 256; n++) + { + boldcols[n] = (n & 8) != 0; + blinkcols[n][0] = normcols[n][0] = blue; + blinkcols[n][1] = normcols[n][1] = grey; + } + + /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the + * passed value. Exclude x0 and x8, which are always grey on + * blue. */ + for (n = 0x11; n <= 0xFF; n++) + { + if ((n & 7) == 0) continue; + if (t1000->attrmap & 4) /* Inverse */ + { + blinkcols[n][0] = normcols[n][0] = blue; + blinkcols[n][1] = normcols[n][1] = grey; + } + else /* Normal */ + { + blinkcols[n][0] = normcols[n][0] = grey; + blinkcols[n][1] = normcols[n][1] = blue; + } + if (t1000->attrmap & 8) boldcols[n] = 1; /* Bold */ + } + /* 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 (t1000->attrmap & 1) + { + blinkcols[n][0] = normcols[n][0] = blue; + blinkcols[n][1] = normcols[n][1] = grey; + blinkcols[n+128][0] = blue; + blinkcols[n+128][1] = grey; + } + else + { + blinkcols[n][0] = normcols[n][0] = grey; + blinkcols[n][1] = normcols[n][1] = blue; + blinkcols[n+128][0] = grey; + blinkcols[n+128][1] = blue; + } + if (t1000->attrmap & 2) boldcols[n] = 1; + } + /* Colours 07 and 0F are always blue on grey. If blinking is + * enabled so are 87 and 8F. */ + for (n = 0x07; n <= 0x0F; n += 8) + { + blinkcols[n][0] = normcols[n][0] = grey; + blinkcols[n][1] = normcols[n][1] = blue; + blinkcols[n+128][0] = grey; + blinkcols[n+128][1] = blue; + } + /* When not blinking, colours 81-8F are always blue on grey. */ + for (n = 0x81; n <= 0x8F; n ++) + { + normcols[n][0] = grey; + normcols[n][1] = blue; + boldcols[n] = (n & 0x08) != 0; + } + + + /* Finally do the ones which are solid grey. These differ between + * the normal and blinking mappings */ + for (n = 0; n <= 0xFF; n += 0x11) + { + normcols[n][0] = normcols[n][1] = grey; + } + /* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are grey */ + for (n = 0; n <= 0x77; n += 0x11) + { + blinkcols[n][0] = blinkcols[n][1] = grey; + blinkcols[n+128][0] = blinkcols[n+128][1] = grey; + } +} + + +static void *t1000_init(device_t *info) +{ + t1000_t *t1000 = malloc(sizeof(t1000_t)); + memset(t1000, 0, sizeof(t1000_t)); + cga_init(&t1000->cga); + + t1000->internal = 1; + + /* 16k video RAM */ + t1000->vram = malloc(0x4000); + + timer_add(t1000_poll, &t1000->cga.vidtime, TIMER_ALWAYS_ENABLED, t1000); + + /* Occupy memory between 0xB8000 and 0xBFFFF */ + mem_mapping_add(&t1000->mapping, 0xb8000, 0x8000, t1000_read, NULL, NULL, t1000_write, NULL, NULL, NULL, 0, t1000); + /* Respond to CGA I/O ports */ + io_sethandler(0x03d0, 0x000c, t1000_in, NULL, NULL, t1000_out, NULL, NULL, t1000); + + /* Default attribute mapping is 4 */ + t1000->attrmap = 4; + t1000_recalcattrs(t1000); + + /* Start off in 80x25 text mode */ + t1000->cga.cgastat = 0xF4; + t1000->cga.vram = t1000->vram; + t1000->enabled = 1; + t1000->video_options = 0x01; + language = device_get_config_int("display_language") ? 2 : 0; + return t1000; +} + +static void t1000_close(void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + + free(t1000->vram); + free(t1000); +} + +static void t1000_speed_changed(void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + + t1000_recalctimings(t1000); +} + +static device_config_t t1000_config[] = +{ + { + .name = "display_language", + .description = "Language", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "USA", + .value = 0 + }, + { + .description = "Danish", + .value = 1 + } + }, + .default_int = 0 + }, + { + .type = -1 + } +}; + + +device_t t1000_video_device = { + "Toshiba T1000 Video", + 0, 0, + t1000_init, t1000_close, NULL, + NULL, + t1000_speed_changed, + NULL, + NULL, + t1000_config +}; + + +device_t t1200_video_device = { + "Toshiba T1200 Video", + 0, 0, + t1000_init, t1000_close, NULL, + NULL, + t1000_speed_changed, + NULL, + NULL, + t1000_config +}; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index aa53e86d6..8bb8d4982 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.24 2018/03/11 + * Version: @(#)machine_table.c 1.0.25 2018/03/13 * * Authors: Sarah Walker, * Miran Grca, @@ -44,10 +44,10 @@ machine_t machines[] = { { "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, { "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, { "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 0, machine_europc_init, NULL, NULL }, + { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL, NULL }, { "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device, NULL }, { "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device, NULL }, - { "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 0, machine_xt_t1000_init, NULL, NULL }, + { "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, NULL, NULL }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL }, #endif @@ -60,7 +60,7 @@ machine_t machines[] = { { "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close }, { "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL, NULL }, { "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL, NULL }, - { "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 0, machine_xt_t1200_init, NULL, NULL }, + { "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, NULL, NULL }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) { "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL }, #endif diff --git a/src/nvr.c b/src/nvr.c index 6d20dff8e..9eb8db2d5 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -1,200 +1,50 @@ /* - * 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. + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. * - * This file is part of the 86Box distribution. + * This file is part of the VARCem Project. * - * Implement a more-or-less defacto-standard RTC/NVRAM. + * Implement a generic NVRAM/CMOS/RTC device. * - * When IBM released the PC/AT machine, it came standard with a - * battery-backed RTC chip to keep the time of day, something - * that was optional on standard PC's with a myriad variants - * being put on the market, often on cheap multi-I/O cards. + * NOTE: I should re-do 'intclk' using a TM struct. * - * The PC/AT had an on-board DS12885-series chip ("the black - * block") which was an RTC/clock chip with onboard oscillator - * and a backup battery (hence the big size.) The chip also had - * a smal amount of RAM bytes available to the user, which was - * used by IBM's ROM BIOS to store machine configuration data. + * Version: @(#)nvr.c 1.0.2 2018/03/11 * - * Since then, pretty much any PC has an implementation of that - * device, which became known as the "nvr" or "cmos". + * Author: Fred N. van Kempen, * - * NOTES Info extracted from the data sheets: - * - * * The century register at location 32h is a BCD register - * designed to automatically load the BCD value 20 as the - * year register changes from 99 to 00. The MSB of this - * register is not affected when the load of 20 occurs, - * and remains at the value written by the user. - * - * * Rate Selector (RS3:RS0) - * These four rate-selection bits select one of the 13 - * taps on the 15-stage divider or disable the divider - * output. The tap selected can be used to generate an - * output square wave (SQW pin) and/or a periodic interrupt. - * - * The user can do one of the following: - * - enable the interrupt with the PIE bit; - * - enable the SQW output pin with the SQWE bit; - * - enable both at the same time and the same rate; or - * - enable neither. - * - * Table 3 lists the periodic interrupt rates and the square - * wave frequencies that can be chosen with the RS bits. - * These four read/write bits are not affected by !RESET. - * - * * Oscillator (DV2:DV0) - * These three bits are used to turn the oscillator on or - * off and to reset the countdown chain. A pattern of 010 - * is the only combination of bits that turn the oscillator - * on and allow the RTC to keep time. A pattern of 11x - * enables the oscillator but holds the countdown chain in - * reset. The next update occurs at 500ms after a pattern - * of 010 is written to DV0, DV1, and DV2. - * - * * Update-In-Progress (UIP) - * This bit is a status flag that can be monitored. When the - * UIP bit is a 1, the update transfer occurs soon. When - * UIP is a 0, the update transfer does not occur for at - * least 244us. The time, calendar, and alarm information - * in RAM is fully available for access when the UIP bit - * is 0. The UIP bit is read-only and is not affected by - * !RESET. Writing the SET bit in Register B to a 1 - * inhibits any update transfer and clears the UIP status bit. - * - * * Daylight Saving Enable (DSE) - * This bit is a read/write bit that enables two daylight - * saving adjustments when DSE is set to 1. On the first - * Sunday in April (or the last Sunday in April in the - * MC146818A), the time increments from 1:59:59 AM to - * 3:00:00 AM. On the last Sunday in October when the time - * first reaches 1:59:59 AM, it changes to 1:00:00 AM. - * - * When DSE is enabled, the internal logic test for the - * first/last Sunday condition at midnight. If the DSE bit - * is not set when the test occurs, the daylight saving - * function does not operate correctly. These adjustments - * do not occur when the DSE bit is 0. This bit is not - * affected by internal functions or !RESET. - * - * * 24/12 - * The 24/12 control bit establishes the format of the hours - * byte. A 1 indicates the 24-hour mode and a 0 indicates - * the 12-hour mode. This bit is read/write and is not - * affected by internal functions or !RESET. - * - * * Data Mode (DM) - * This bit indicates whether time and calendar information - * is in binary or BCD format. The DM bit is set by the - * program to the appropriate format and can be read as - * required. This bit is not modified by internal functions - * or !RESET. A 1 in DM signifies binary data, while a 0 in - * DM specifies BCD data. - * - * * Square-Wave Enable (SQWE) - * When this bit is set to 1, a square-wave signal at the - * frequency set by the rate-selection bits RS3-RS0 is driven - * out on the SQW pin. When the SQWE bit is set to 0, the - * SQW pin is held low. SQWE is a read/write bit and is - * cleared by !RESET. SQWE is low if disabled, and is high - * impedance when VCC is below VPF. SQWE is cleared to 0 on - * !RESET. - * - * * Update-Ended Interrupt Enable (UIE) - * This bit is a read/write bit that enables the update-end - * flag (UF) bit in Register C to assert !IRQ. The !RESET - * pin going low or the SET bit going high clears the UIE bit. - * The internal functions of the device do not affect the UIE - * bit, but is cleared to 0 on !RESET. - * - * * Alarm Interrupt Enable (AIE) - * This bit is a read/write bit that, when set to 1, permits - * the alarm flag (AF) bit in Register C to assert !IRQ. An - * alarm interrupt occurs for each second that the three time - * bytes equal the three alarm bytes, including a don't-care - * alarm code of binary 11XXXXXX. The AF bit does not - * initiate the !IRQ signal when the AIE bit is set to 0. - * The internal functions of the device do not affect the AIE - * bit, but is cleared to 0 on !RESET. - * - * * Periodic Interrupt Enable (PIE) - * The PIE bit is a read/write bit that allows the periodic - * interrupt flag (PF) bit in Register C to drive the !IRQ pin - * low. When the PIE bit is set to 1, periodic interrupts are - * generated by driving the !IRQ pin low at a rate specified - * by the RS3-RS0 bits of Register A. A 0 in the PIE bit - * blocks the !IRQ output from being driven by a periodic - * interrupt, but the PF bit is still set at the periodic - * rate. PIE is not modified b any internal device functions, - * but is cleared to 0 on !RESET. - * - * * SET - * When the SET bit is 0, the update transfer functions - * normally by advancing the counts once per second. When - * the SET bit is written to 1, any update transfer is - * inhibited, and the program can initialize the time and - * calendar bytes without an update occurring in the midst of - * initializing. Read cycles can be executed in a similar - * manner. SET is a read/write bit and is not affected by - * !RESET or internal functions of the device. - * - * * Update-Ended Interrupt Flag (UF) - * This bit is set after each update cycle. When the UIE - * bit is set to 1, the 1 in UF causes the IRQF bit to be - * a 1, which asserts the !IRQ pin. This bit can be - * cleared by reading Register C or with a !RESET. - * - * * Alarm Interrupt Flag (AF) - * A 1 in the AF bit indicates that the current time has - * matched the alarm time. If the AIE bit is also 1, the - * !IRQ pin goes low and a 1 appears in the IRQF bit. This - * bit can be cleared by reading Register C or with a - * !RESET. - * - * * Periodic Interrupt Flag (PF) - * This bit is read-only and is set to 1 when an edge is - * detected on the selected tap of the divider chain. The - * RS3 through RS0 bits establish the periodic rate. PF is - * set to 1 independent of the state of the PIE bit. When - * both PF and PIE are 1s, the !IRQ signal is active and - * sets the IRQF bit. This bit can be cleared by reading - * Register C or with a !RESET. - * - * * Interrupt Request Flag (IRQF) - * The interrupt request flag (IRQF) is set to a 1 when one - * or more of the following are true: - * - PF == PIE == 1 - * - AF == AIE == 1 - * - UF == UIE == 1 - * Any time the IRQF bit is a 1, the !IRQ pin is driven low. - * All flag bits are cleared after Register C is read by the - * program or when the !RESET pin is low. - * - * * Valid RAM and Time (VRT) - * This bit indicates the condition of the battery connected - * to the VBAT pin. This bit is not writeable and should - * always be 1 when read. If a 0 is ever present, an - * exhausted internal lithium energy source is indicated and - * both the contents of the RTC data and RAM data are - * questionable. This bit is unaffected by !RESET. - * - * This file implements an internal RTC clock, plus a generic - * version of the RTC/NVRAM chip, including the later update - * (DS12887A) which implemented a "century" register to be - * compatible with Y2K. - * - * Version: @(#)nvr.c 1.0.15 2018/02/26 - * - * Authors: Miran Grca, - * Mahod, - * Fred N. van Kempen, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include @@ -203,33 +53,37 @@ #include #include #include "86box.h" +#include "machine/machine.h" #include "pic.h" #include "pit.h" #include "timer.h" -#include "machine/machine.h" #include "plat.h" #include "nvr.h" -int enable_sync; /* configuration variable: enable time sync */ -int nvr_dosave; /* NVR is dirty, needs saved */ - - -static nvr_t *saved_nvr = NULL; -static int8_t days_in_month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; -static struct { +/* Define the internal clock. */ +typedef struct { int16_t year; int8_t sec; int8_t min; int8_t hour; int8_t mday; int8_t mon; -} intclk; /* the internal clock */ +} intclk_t; + + +int enable_sync; /* configuration variable: enable time sync */ +int nvr_dosave; /* NVR is dirty, needs saved */ + + +static int8_t days_in_month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; +static intclk_t intclk; +static nvr_t *saved_nvr = NULL; /* Determine whether or not the year is leap. */ -static int8_t -is_leap(int8_t year) +int +nvr_is_leap(int year) { if (year % 400 == 0) return(1); if (year % 100 == 0) return(0); @@ -240,13 +94,13 @@ is_leap(int8_t year) /* Determine the days in the current month. */ -static int8_t -get_days(int8_t month, int8_t year) +int +nvr_get_days(int month, int year) { if (month != 2) return(days_in_month[month - 1]); - return(is_leap(year) ? 29 : 28); + return(nvr_is_leap(year) ? 29 : 28); } @@ -267,7 +121,7 @@ rtc_tick(void) intclk.hour = 0; intclk.mday++; } - if (intclk.mday == (get_days(intclk.mon, intclk.year) + 1)) { + if (intclk.mday == (nvr_get_days(intclk.mon, intclk.year) + 1)) { intclk.mday = 1; intclk.mon++; } @@ -278,107 +132,6 @@ rtc_tick(void) } -/* Store the broken-down local time into the NVR. */ -static void -rtc_getnvr(uint8_t *nvr, struct tm *tm) -{ - if (nvr[RTC_REGB] & REGB_DM) { - /* NVR is in Binary data mode. */ - nvr[RTC_SECONDS] = tm->tm_sec; - nvr[RTC_MINUTES] = tm->tm_min; - nvr[RTC_DOW] = tm->tm_wday+1; - nvr[RTC_DOM] = tm->tm_mday; - nvr[RTC_MONTH] = tm->tm_mon+1; - nvr[RTC_YEAR] = tm->tm_year%100; - - if (nvr[RTC_REGB] & REGB_2412) { - /* NVR is in 24h mode. */ - nvr[RTC_HOURS] = tm->tm_hour; - } else { - /* NVR is in 12h mode. */ - nvr[RTC_HOURS] = (tm->tm_hour % 12) ? (tm->tm_hour % 12) : 12; - if (tm->tm_hour > 11) - nvr[RTC_HOURS] |= RTC_AMPM; - } - } else { - /* NVR is in BCD data mode. */ - nvr[RTC_SECONDS] = RTC_BCD(tm->tm_sec); - nvr[RTC_MINUTES] = RTC_BCD(tm->tm_min); - nvr[RTC_DOW] = RTC_BCD(tm->tm_wday+1); - nvr[RTC_DOM] = RTC_BCD(tm->tm_mday); - nvr[RTC_MONTH] = RTC_BCD(tm->tm_mon+1); - nvr[RTC_YEAR] = RTC_BCD(tm->tm_year%100); - - if (nvr[RTC_REGB] & REGB_2412) { - /* NVR is in 24h mode. */ - nvr[RTC_HOURS] = RTC_BCD(tm->tm_hour); - } else { - /* NVR is in 12h mode. */ - nvr[RTC_HOURS] = (tm->tm_hour % 12) - ? RTC_BCD(tm->tm_hour % 12) - : RTC_BCD(12); - if (tm->tm_hour > 11) - nvr[RTC_HOURS] |= RTC_AMPM; - } - } -} - - -/* Load local time from the NVR. */ -static void -rtc_setnvr(uint8_t *nvr) -{ - int8_t temp; - - if (nvr[RTC_REGB] & REGB_DM) { - intclk.sec = nvr[RTC_SECONDS]; - intclk.min = nvr[RTC_MINUTES]; - temp = nvr[RTC_HOURS]; - intclk.mday = nvr[RTC_DOM]; - intclk.mon = nvr[RTC_MONTH]; - intclk.year = nvr[RTC_YEAR]; - intclk.year += 1900; - } else { - intclk.sec = RTC_DCB(nvr[RTC_SECONDS]); - intclk.min = RTC_DCB(nvr[RTC_MINUTES]); - temp = RTC_DCB(nvr[RTC_HOURS]); - intclk.mday = RTC_DCB(nvr[RTC_DOM]); - intclk.mon = RTC_DCB(nvr[RTC_MONTH]); - intclk.year = RTC_DCB(nvr[RTC_YEAR]); - intclk.year += (RTC_DCB(nvr[RTC_CENTURY]) * 100); - } - - /* Adjust for 12/24 hour mode. */ - if (nvr[RTC_REGB] & REGB_2412) - intclk.hour = temp; - else - intclk.hour = ((temp & ~RTC_AMPM) % 12) + ((temp & RTC_AMPM) ? 12 : 0); -} - - -static void -rtc_sync(uint8_t *nvr) -{ - struct tm *tm; - time_t now; - - /* Get the current time of day, and convert to local time. */ - (void)time(&now); - tm = localtime(&now); - - /* Set the internal clock. */ - intclk.sec = tm->tm_sec; - intclk.min = tm->tm_min; - intclk.hour = tm->tm_hour; - intclk.mday = tm->tm_mday; - intclk.mon = tm->tm_mon+1; - intclk.year = tm->tm_year+1900; - - /* Set the NVR registers. */ - rtc_getnvr(nvr, tm); -} - - /* This is the RTC one-second timer. */ static void onesec_timer(void *priv) @@ -386,20 +139,13 @@ onesec_timer(void *priv) nvr_t *nvr = (nvr_t *)priv; if (++nvr->onesec_cnt >= 100) { - if (! (nvr->regs[RTC_REGB] & REGB_SET)) { - nvr->upd_stat = REGA_UIP; + /* Update the internal clock. */ + rtc_tick(); - /* Update the system RTC. */ - rtc_tick(); + /* Update the RTC device if needed. */ + if (nvr->tick != NULL) + (*nvr->tick)(nvr); - if (nvr->hook != NULL) - (*nvr->hook)(nvr); - - /* Re-calculate the timer. */ - nvr_recalc(); - - nvr->upd_ecount = (int64_t)((244.0 + 1984.0) * TIMER_USEC); - } nvr->onesec_cnt = 0; } @@ -407,241 +153,47 @@ onesec_timer(void *priv) } -/* Check if the current time matches a set alarm time. */ -static int8_t -check_alarm(nvr_t *nvr, int8_t addr) -{ -#define ALARM_DONTCARE 0xc0 - return((nvr->regs[addr+1] == nvr->regs[addr]) || - ((nvr->regs[addr+1] & ALARM_DONTCARE) == ALARM_DONTCARE)); -} - - -/* This is the general update timer. */ -static void -update_timer(void *priv) -{ - nvr_t *nvr = (nvr_t *)priv; - struct tm tm; - int8_t dom, mon, sum, wd; - int16_t cent, yr; - - if (! (nvr->regs[RTC_REGB] & REGB_SET)) { - /* Get the current time from the internal clock. */ - tm.tm_sec = intclk.sec; - tm.tm_min = intclk.min; - tm.tm_hour = intclk.hour; - dom = intclk.mday; - mon = intclk.mon; - yr = intclk.year % 100; - cent = ((intclk.year - yr) / 100) % 4; - sum = dom+mon+yr+cent; - wd = ((sum + 6) % 7); - tm.tm_wday = wd; - tm.tm_mday = intclk.mday; - tm.tm_mon = intclk.mon-1; - tm.tm_year = intclk.year-1900; - rtc_getnvr(nvr->regs, &tm); - - /* Clear update status. */ - nvr->upd_stat = 0; - - if (check_alarm(nvr, RTC_SECONDS) && - check_alarm(nvr, RTC_MINUTES) && - check_alarm(nvr, RTC_HOURS)) { - nvr->regs[RTC_REGC] |= REGC_AF; - if (nvr->regs[RTC_REGB] & REGB_AIE) { - nvr->regs[RTC_REGC] |= REGC_IRQF; - - /* Generate an interrupt. */ - if (nvr->irq != -1) - picint(1<irq); - } - } - - /* - * The flag and interrupt should be issued - * on update ended, not started. - */ - nvr->regs[RTC_REGC] |= REGC_UF; - if (nvr->regs[RTC_REGB] & REGB_UIE) { - nvr->regs[RTC_REGC] |= REGC_IRQF; - - /* Generate an interrupt. */ - if (nvr->irq != -1) - picint(1<irq); - } - } - - nvr->upd_ecount = 0; -} - - -static void -ticker_timer(void *priv) -{ - nvr_t *nvr = (nvr_t *)priv; - int64_t c; - - if (! (nvr->regs[RTC_REGA] & REGA_RS)) { - nvr->rtctime = 0x7fffffff; - return; - } - - /* Update our ticker interval. */ - c = 1 << ((nvr->regs[RTC_REGA] & REGA_RS) - 1); - nvr->rtctime += (int64_t)(RTCCONST*c*(1<regs[RTC_REGC] |= REGC_PF; - if (nvr->regs[RTC_REGB] & REGB_PIE) { - nvr->regs[RTC_REGC] |= REGC_IRQF; - - /* Generate an interrupt. */ - if (nvr->irq != -1) - picint(1<irq); - } -} - - -/* Set one of the chip's registers. */ -static void -nvr_write(nvr_t *nvr, uint16_t reg, uint8_t val) -{ - uint8_t old; - int64_t c; - - old = nvr->regs[reg]; - switch(reg) { - case RTC_REGA: - nvr->regs[reg] = val; - if (val & REGA_RS) { - c = 1 << ((val & REGA_RS) - 1); - nvr->rtctime += (int64_t)(RTCCONST*c*(1<rtctime = 0x7fffffff; - } - break; - - case RTC_REGB: - nvr->regs[reg] = val; - if (((old^val) & REGB_SET) && (val®B_SET)) { - /* This has to be done according to the datasheet. */ - nvr->regs[RTC_REGA] &= ~REGA_UIP; - - /* This also has to happen per the specification. */ - nvr->regs[RTC_REGB] &= ~REGB_UIE; - } - break; - - case RTC_REGC: /* R/O */ - case RTC_REGD: /* R/O */ - break; - - default: /* non-RTC registers are just NVRAM */ - if (nvr->regs[reg] != val) { - nvr->regs[reg] = val; - - nvr_dosave = 1; - } - break; - } - - if ((reg < RTC_REGA) || (reg == RTC_CENTURY)) { - if ((reg != 1) && (reg != 3) && (reg != 5)) { - if ((old != val) && !enable_sync) { - /* Update internal clock. */ - rtc_setnvr(nvr->regs); - - nvr_dosave = 1; - } - } - } -} - - -/* Get one of the chip's registers. */ -static uint8_t -nvr_read(nvr_t *nvr, uint16_t reg) -{ - uint8_t ret = 0xff; - - switch(reg) { - case RTC_REGA: - ret = (nvr->regs[RTC_REGA] & 0x7f) | nvr->upd_stat; - break; - - case RTC_REGC: - picintc(1<irq); - ret = nvr->regs[RTC_REGC]; - nvr->regs[RTC_REGC] = 0x00; - break; - - case RTC_REGD: - nvr->regs[RTC_REGD] |= REGD_VRT; - ret = nvr->regs[RTC_REGD]; - break; - - default: - ret = nvr->regs[reg]; - break; - } - - return(ret); -} - - -/* Initialize the virtual RTC/NVRAM chip. */ +/* Initialize the generic NVRAM/RTC device. */ void nvr_init(nvr_t *nvr) { - char temp[32]; - int64_t c; + char temp[64]; + struct tm *tm; + time_t now; + int c; - /* Clear some of it. */ - nvr->upd_stat = 0; - nvr->upd_ecount = 0; - nvr->onesec_time = 0; - nvr->onesec_cnt = 0; - memset(&intclk, 0x00, sizeof(intclk)); - - /* Pre-initialize the NVR file's name here. */ - sprintf(temp, "%s.nvr", machine_get_internal_name_ex(machine)); + /* Set up the NVR file's name. */ + sprintf(temp, "%s.nvr", machine_get_internal_name()); c = strlen(temp)+1; - nvr->fname = (wchar_t *)malloc(c*sizeof(wchar_t)); - mbstowcs(nvr->fname, temp, c); + nvr->fn = (wchar_t *)malloc(c*sizeof(wchar_t)); + mbstowcs(nvr->fn, temp, c); - /* Set up our local handlers. */ - nvr->get = nvr_read; - nvr->set = nvr_write; + /* Initialize the internal clock as needed. */ + memset(&intclk, 0x00, sizeof(intclk)); + if (enable_sync) { + /* Get the current time of day, and convert to local time. */ + (void)time(&now); + tm = localtime(&now); - /* Set up our timers. */ - timer_add(ticker_timer, &nvr->rtctime, TIMER_ALWAYS_ENABLED, nvr); + /* Set the internal clock. */ + nvr_time_set(tm); + } else { + /* Reset the internal clock to 1980/01/01 00:00. */ + intclk.mon = 1; + intclk.year = 1980; + } + /* Set up our timer. */ timer_add(onesec_timer, &nvr->onesec_time, TIMER_ALWAYS_ENABLED, nvr); - timer_add(update_timer, &nvr->upd_ecount, &nvr->upd_ecount, nvr); - /* It does not need saving yet. */ nvr_dosave = 0; /* Save the NVR data pointer. */ saved_nvr = nvr; -} - -/* Re-calculate the timer values. */ -void -nvr_recalc(void) -{ - int64_t c, nt; - - /* Make sure we have been initialized. */ - if (saved_nvr == NULL) return; - - c = 1 << ((saved_nvr->regs[RTC_REGA] & REGA_RS) - 1); - nt = (int64_t)(RTCCONST * c * (1<rtctime > nt) - saved_nvr->rtctime = nt; + /* Try to load the saved data. */ + (void)nvr_load(); } @@ -659,7 +211,6 @@ nvr_recalc(void) int nvr_load(void) { - int64_t c; FILE *f; /* Make sure we have been initialized. */ @@ -669,41 +220,23 @@ nvr_load(void) memset(saved_nvr->regs, 0xff, sizeof(saved_nvr->regs)); /* Set the defaults. */ - memset(saved_nvr->regs, 0x00, RTC_REGS); - saved_nvr->regs[RTC_DOM] = 1; - saved_nvr->regs[RTC_MONTH] = 1; - saved_nvr->regs[RTC_YEAR] = RTC_BCD(80); - saved_nvr->regs[RTC_CENTURY] = RTC_BCD(19); - - if (saved_nvr->load == NULL) { - /* We are responsible for loading. */ - f = NULL; - if (saved_nvr->mask != 0) { - pclog("Opening NVR file: %ls...\n", nvr_path(saved_nvr->fname)); - f = plat_fopen(nvr_path(saved_nvr->fname), L"rb"); - } + if (saved_nvr->reset != NULL) + saved_nvr->reset(saved_nvr); + /* Load the (relevant) part of the NVR contents. */ + if (saved_nvr->size != 0) { + pclog("NVR: loading from '%ls'\n", nvr_path(saved_nvr->fn)); + f = plat_fopen(nvr_path(saved_nvr->fn), L"rb"); if (f != NULL) { /* Read NVR contents from file. */ - fread(saved_nvr->regs, sizeof(saved_nvr->regs), 1, f); + (void)fread(saved_nvr->regs, saved_nvr->size, 1, f); (void)fclose(f); } - } else { - /* OK, use alternate function. */ - (*saved_nvr->load)(saved_nvr->fname); } - /* Update the internal clock state based on the NVR registers. */ - if (enable_sync) - rtc_sync(saved_nvr->regs); - else - rtc_setnvr(saved_nvr->regs); - /* Get the local RTC running! */ - saved_nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1); - saved_nvr->regs[RTC_REGB] = REGB_2412; - c = 1 << ((saved_nvr->regs[RTC_REGA] & REGA_RS) - 1); - saved_nvr->rtctime += (int64_t)(RTCCONST * c * (1<start != NULL) + saved_nvr->start(saved_nvr); return(1); } @@ -718,22 +251,14 @@ nvr_save(void) /* Make sure we have been initialized. */ if (saved_nvr == NULL) return(0); - if (saved_nvr->save == NULL) { - /* We are responsible for saving. */ - f = NULL; - if (saved_nvr->mask != 0) { - pclog("Saving NVR file: %ls...\n", nvr_path(saved_nvr->fname)); - f = plat_fopen(nvr_path(saved_nvr->fname), L"wb"); - } - + if (saved_nvr->size != 0) { + pclog("NVR: saving to '%ls'\n", nvr_path(saved_nvr->fn)); + f = plat_fopen(nvr_path(saved_nvr->fn), L"wb"); if (f != NULL) { /* Save NVR contents to file. */ - (void)fwrite(saved_nvr->regs, sizeof(saved_nvr->regs), 1, f); - (void)fclose(f); + (void)fwrite(saved_nvr->regs, saved_nvr->size, 1, f); + fclose(f); } - } else { - /* OK, use alternate function. */ - (*saved_nvr->save)(saved_nvr->fname); } /* Device is clean again. */ @@ -743,6 +268,42 @@ nvr_save(void) } +/* Get current time from internal clock. */ +void +nvr_time_get(struct tm *tm) +{ + int8_t dom, mon, sum, wd; + int16_t cent, yr; + + tm->tm_sec = intclk.sec; + tm->tm_min = intclk.min; + tm->tm_hour = intclk.hour; + dom = intclk.mday; + mon = intclk.mon; + yr = (intclk.year % 100); + cent = ((intclk.year - yr) / 100) % 4; + sum = dom+mon+yr+cent; + wd = ((sum + 6) % 7); + tm->tm_wday = wd; + tm->tm_mday = intclk.mday; + tm->tm_mon = (intclk.mon - 1); + tm->tm_year = (intclk.year - 1900); +} + + +/* Set internal clock time. */ +void +nvr_time_set(struct tm *tm) +{ + intclk.sec = tm->tm_sec; + intclk.min = tm->tm_min; + intclk.hour = tm->tm_hour; + intclk.mday = tm->tm_mday; + intclk.mon = (tm->tm_mon + 1); + intclk.year = (tm->tm_year + 1900); +} + + /* Get an absolute path to the NVR folder. */ wchar_t * nvr_path(wchar_t *str) @@ -759,11 +320,7 @@ nvr_path(wchar_t *str) plat_dir_create(temp); /* Now append the actual filename. */ -#ifdef _WIN32 - wcscat(temp, L"\\"); -#else - wcscat(temp, L"/"); -#endif + plat_path_slash(temp); wcscat(temp, str); return(temp); diff --git a/src/nvr.h b/src/nvr.h index e247494b4..8119948a2 100644 --- a/src/nvr.h +++ b/src/nvr.h @@ -1,119 +1,99 @@ -/* - * 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. - * - * Definitions for a defacto-standard RTC/NVRAM device. - * - * Version: @(#)nvr.h 1.0.5 2017/11/22 - * - * Authors: Miran Grca, - * Mahod, - * Fred N. van Kempen, - * - * Copyright 2016-2017 Miran Grca. - * Copyright 2016-2017 Mahod. - * Copyright 2017 Fred N. van Kempen. - */ -#ifndef EMU_NVR_H -# define EMU_NVR_H - - -/* Conversion from BCD to Binary and vice versa. */ -#define RTC_BCD(x) (((x) % 10) | (((x) / 10) << 4)) -#define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) - -/* RTC registers and bit definitions. */ -#define RTC_SECONDS 0 -#define RTC_ALSECONDS 1 -#define RTC_MINUTES 2 -#define RTC_ALMINUTES 3 -#define RTC_HOURS 4 -# define RTC_AMPM 0x80 /* PM flag if 12h format in use */ -#define RTC_ALHOURS 5 -#define RTC_DOW 6 -#define RTC_DOM 7 -#define RTC_MONTH 8 -#define RTC_YEAR 9 -#define RTC_REGA 10 -# define REGA_UIP 0x80 -# define REGA_DV2 0x40 -# define REGA_DV1 0x20 -# define REGA_DV0 0x10 -# define REGA_DV 0x70 -# define REGA_RS3 0x08 -# define REGA_RS2 0x04 -# define REGA_RS1 0x02 -# define REGA_RS0 0x01 -# define REGA_RS 0x0f -#define RTC_REGB 11 -# define REGB_SET 0x80 -# define REGB_PIE 0x40 -# define REGB_AIE 0x20 -# define REGB_UIE 0x10 -# define REGB_SQWE 0x08 -# define REGB_DM 0x04 -# define REGB_2412 0x02 -# define REGB_DSE 0x01 -#define RTC_REGC 12 -# define REGC_IRQF 0x80 -# define REGC_PF 0x40 -# define REGC_AF 0x20 -# define REGC_UF 0x10 -#define RTC_REGD 13 -# define REGD_VRT 0x80 -#define RTC_CENTURY 0x32 /* century register */ -#define RTC_REGS 14 /* number of registers */ - - - -/* Define a (defacto-standard) RTC/NVRAM chip. */ -typedef struct _nvr_ { - uint8_t regs[RTC_REGS+114]; /* these are the registers */ - - int64_t mask, - irq, - addr; - - wchar_t *fname; - - int64_t upd_stat, - upd_ecount, - onesec_time, - onesec_cnt, - rtctime, - oldmachine; - - /* Hooks to internal RTC I/O functions. */ - void (*set)(struct _nvr_ *, uint16_t, uint8_t); - uint8_t (*get)(struct _nvr_ *, uint16_t); - - /* Hooks to alternative load/save functions. */ - int8_t (*load)(wchar_t *fname); - int8_t (*save)(wchar_t *fname); - - /* Hook to RTC ticker handler. */ - void (*hook)(struct _nvr_ *); -} nvr_t; - - -extern int enable_sync; -extern int nvr_dosave; - - -extern void nvr_init(nvr_t *); -extern int nvr_load(void); -extern int nvr_save(void); -extern void nvr_recalc(void); - -extern wchar_t *nvr_path(wchar_t *str); -extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); - -extern void nvr_at_init(int64_t irq); -extern void nvr_at_close(void); - - -#endif /*EMU_NVR_H*/ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the generic NVRAM/CMOS driver. + * + * Version: @(#)nvr.h 1.0.2 2018/03/11 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EMU_NVR_H +# define EMU_NVR_H + + +#define NVR_MAXSIZE 128 /* max size of NVR data */ + +/* Conversion from BCD to Binary and vice versa. */ +#define RTC_BCD(x) (((x) % 10) | (((x) / 10) << 4)) +#define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f)) +#define RTC_BCDINC(x,y) RTC_BCD(RTC_DCB(x) + y) + + +/* Define a generic RTC/NVRAM device. */ +typedef struct _nvr_ { + uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ + wchar_t *fn; /* pathname of image file */ + uint16_t size; /* device configuration */ + int8_t irq; + + int8_t upd_stat, /* FIXME: move to private struct */ + addr; + int64_t upd_ecount, /* FIXME: move to private struct */ + onesec_time, + onesec_cnt, + rtctime; + + /* Hooks to device functions. */ + void (*reset)(struct _nvr_ *); + void (*start)(struct _nvr_ *); + void (*tick)(struct _nvr_ *); +} nvr_t; + + +extern int nvr_dosave; + + +extern void nvr_init(nvr_t *); +extern int nvr_load(void); +extern int nvr_save(void); + +extern int nvr_is_leap(int year); +extern int nvr_get_days(int month, int year); +extern void nvr_time_get(struct tm *); +extern void nvr_time_set(struct tm *); + +extern wchar_t *nvr_path(wchar_t *str); +extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); + +extern void nvr_at_init(int irq); +extern void nvr_at_close(void); + + +#endif /*EMU_NVR_H*/ diff --git a/src/nvr_at.c b/src/nvr_at.c index 131d1415c..a982a962f 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -1,124 +1,661 @@ -/* - * 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 PC/AT RTC/NVRAM ("CMOS") emulation. - * - * The original PC/AT series had DS12885 series modules; later - * versions and clones used the 12886 and/or 1288(C)7 series, - * or the MC146818 series, all with an external battery. Many - * of those batteries would create corrosion issues later on - * in mainboard life... - * - * Version: @(#)nvr_at.c 1.0.9 2018/02/27 - * - * Authors: Miran Grca, - * Fred N. van Kempen, - * - * Copyright 2016-2018 Miran Grca. - * Copyright 2017,2018 Fred N. van Kempen. - */ -#include -#include -#include -#include -#include -#include "cpu/cpu.h" -#include "io.h" -#include "device.h" -#include "machine/machine.h" -#include "mem.h" -#include "nmi.h" -#include "nvr.h" -#include "rom.h" - - -static nvr_t *nvrp; - - -static void -nvr_write(uint16_t addr, uint8_t val, void *priv) -{ - nvr_t *nvr = (nvr_t *)priv; - - cycles -= ISA_CYCLES(8); - - if (! (addr & 1)) { - nvr->addr = (val & nvr->mask); - if (!(machines[machine].flags & MACHINE_MCA) && (romset != ROM_IBMPS1_2133)) - nmi_mask = (~val & 0x80); - - return; - } - - /* Write the chip's registers. */ - (*nvr->set)(nvr, nvr->addr, val); -} - - -static uint8_t -nvr_read(uint16_t addr, void *priv) -{ - nvr_t *nvr = (nvr_t *)priv; - uint8_t ret; - - cycles -= ISA_CYCLES(8); - - if (addr & 1) { - /* Read from the chip's registers. */ - ret = (*nvr->get)(nvr, nvr->addr); - } else { - ret = nvr->addr; - } - - return(ret); -} - - -void -nvr_at_close(void) -{ - if (nvrp == NULL) - return; - - if (nvrp->fname != NULL) - free(nvrp->fname); - - free(nvrp); - - nvrp = NULL; -} - - -void -nvr_at_init(int64_t irq) -{ - nvr_t *nvr; - - /* Allocate an NVR for this machine. */ - nvr = (nvr_t *)malloc(sizeof(nvr_t)); - if (nvr == NULL) return; - memset(nvr, 0x00, sizeof(nvr_t)); - - /* This is machine specific. */ - nvr->mask = machines[machine].nvrmask; - nvr->irq = irq; - - /* Set up any local handlers here. */ - - /* Initialize the actual NVR. */ - nvr_init(nvr); - - /* Set up the PC/AT handler for this device. */ - io_sethandler(0x0070, 2, - nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr); - - /* Load the NVR into memory! */ - (void)nvr_load(); - - nvrp = nvr; -} +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implement a more-or-less defacto-standard RTC/NVRAM. + * + * When IBM released the PC/AT machine, it came standard with a + * battery-backed RTC chip to keep the time of day, something + * that was optional on standard PC's with a myriad variants + * being put on the market, often on cheap multi-I/O cards. + * + * The PC/AT had an on-board DS12885-series chip ("the black + * block") which was an RTC/clock chip with onboard oscillator + * and a backup battery (hence the big size.) The chip also had + * a small amount of RAM bytes available to the user, which was + * used by IBM's ROM BIOS to store machine configuration data. + * Later versions and clones used the 12886 and/or 1288(C)7 + * series, or the MC146818 series, all with an external battery. + * Many of those batteries would create corrosion issues later + * on in mainboard life... + * + * Since then, pretty much any PC has an implementation of that + * device, which became known as the "nvr" or "cmos". + * + * NOTES Info extracted from the data sheets: + * + * * The century register at location 32h is a BCD register + * designed to automatically load the BCD value 20 as the + * year register changes from 99 to 00. The MSB of this + * register is not affected when the load of 20 occurs, + * and remains at the value written by the user. + * + * * Rate Selector (RS3:RS0) + * These four rate-selection bits select one of the 13 + * taps on the 15-stage divider or disable the divider + * output. The tap selected can be used to generate an + * output square wave (SQW pin) and/or a periodic interrupt. + * + * The user can do one of the following: + * - enable the interrupt with the PIE bit; + * - enable the SQW output pin with the SQWE bit; + * - enable both at the same time and the same rate; or + * - enable neither. + * + * Table 3 lists the periodic interrupt rates and the square + * wave frequencies that can be chosen with the RS bits. + * These four read/write bits are not affected by !RESET. + * + * * Oscillator (DV2:DV0) + * These three bits are used to turn the oscillator on or + * off and to reset the countdown chain. A pattern of 010 + * is the only combination of bits that turn the oscillator + * on and allow the RTC to keep time. A pattern of 11x + * enables the oscillator but holds the countdown chain in + * reset. The next update occurs at 500ms after a pattern + * of 010 is written to DV0, DV1, and DV2. + * + * * Update-In-Progress (UIP) + * This bit is a status flag that can be monitored. When the + * UIP bit is a 1, the update transfer occurs soon. When + * UIP is a 0, the update transfer does not occur for at + * least 244us. The time, calendar, and alarm information + * in RAM is fully available for access when the UIP bit + * is 0. The UIP bit is read-only and is not affected by + * !RESET. Writing the SET bit in Register B to a 1 + * inhibits any update transfer and clears the UIP status bit. + * + * * Daylight Saving Enable (DSE) + * This bit is a read/write bit that enables two daylight + * saving adjustments when DSE is set to 1. On the first + * Sunday in April (or the last Sunday in April in the + * MC146818A), the time increments from 1:59:59 AM to + * 3:00:00 AM. On the last Sunday in October when the time + * first reaches 1:59:59 AM, it changes to 1:00:00 AM. + * + * When DSE is enabled, the internal logic test for the + * first/last Sunday condition at midnight. If the DSE bit + * is not set when the test occurs, the daylight saving + * function does not operate correctly. These adjustments + * do not occur when the DSE bit is 0. This bit is not + * affected by internal functions or !RESET. + * + * * 24/12 + * The 24/12 control bit establishes the format of the hours + * byte. A 1 indicates the 24-hour mode and a 0 indicates + * the 12-hour mode. This bit is read/write and is not + * affected by internal functions or !RESET. + * + * * Data Mode (DM) + * This bit indicates whether time and calendar information + * is in binary or BCD format. The DM bit is set by the + * program to the appropriate format and can be read as + * required. This bit is not modified by internal functions + * or !RESET. A 1 in DM signifies binary data, while a 0 in + * DM specifies BCD data. + * + * * Square-Wave Enable (SQWE) + * When this bit is set to 1, a square-wave signal at the + * frequency set by the rate-selection bits RS3-RS0 is driven + * out on the SQW pin. When the SQWE bit is set to 0, the + * SQW pin is held low. SQWE is a read/write bit and is + * cleared by !RESET. SQWE is low if disabled, and is high + * impedance when VCC is below VPF. SQWE is cleared to 0 on + * !RESET. + * + * * Update-Ended Interrupt Enable (UIE) + * This bit is a read/write bit that enables the update-end + * flag (UF) bit in Register C to assert !IRQ. The !RESET + * pin going low or the SET bit going high clears the UIE bit. + * The internal functions of the device do not affect the UIE + * bit, but is cleared to 0 on !RESET. + * + * * Alarm Interrupt Enable (AIE) + * This bit is a read/write bit that, when set to 1, permits + * the alarm flag (AF) bit in Register C to assert !IRQ. An + * alarm interrupt occurs for each second that the three time + * bytes equal the three alarm bytes, including a don't-care + * alarm code of binary 11XXXXXX. The AF bit does not + * initiate the !IRQ signal when the AIE bit is set to 0. + * The internal functions of the device do not affect the AIE + * bit, but is cleared to 0 on !RESET. + * + * * Periodic Interrupt Enable (PIE) + * The PIE bit is a read/write bit that allows the periodic + * interrupt flag (PF) bit in Register C to drive the !IRQ pin + * low. When the PIE bit is set to 1, periodic interrupts are + * generated by driving the !IRQ pin low at a rate specified + * by the RS3-RS0 bits of Register A. A 0 in the PIE bit + * blocks the !IRQ output from being driven by a periodic + * interrupt, but the PF bit is still set at the periodic + * rate. PIE is not modified b any internal device functions, + * but is cleared to 0 on !RESET. + * + * * SET + * When the SET bit is 0, the update transfer functions + * normally by advancing the counts once per second. When + * the SET bit is written to 1, any update transfer is + * inhibited, and the program can initialize the time and + * calendar bytes without an update occurring in the midst of + * initializing. Read cycles can be executed in a similar + * manner. SET is a read/write bit and is not affected by + * !RESET or internal functions of the device. + * + * * Update-Ended Interrupt Flag (UF) + * This bit is set after each update cycle. When the UIE + * bit is set to 1, the 1 in UF causes the IRQF bit to be + * a 1, which asserts the !IRQ pin. This bit can be + * cleared by reading Register C or with a !RESET. + * + * * Alarm Interrupt Flag (AF) + * A 1 in the AF bit indicates that the current time has + * matched the alarm time. If the AIE bit is also 1, the + * !IRQ pin goes low and a 1 appears in the IRQF bit. This + * bit can be cleared by reading Register C or with a + * !RESET. + * + * * Periodic Interrupt Flag (PF) + * This bit is read-only and is set to 1 when an edge is + * detected on the selected tap of the divider chain. The + * RS3 through RS0 bits establish the periodic rate. PF is + * set to 1 independent of the state of the PIE bit. When + * both PF and PIE are 1s, the !IRQ signal is active and + * sets the IRQF bit. This bit can be cleared by reading + * Register C or with a !RESET. + * + * * Interrupt Request Flag (IRQF) + * The interrupt request flag (IRQF) is set to a 1 when one + * or more of the following are true: + * - PF == PIE == 1 + * - AF == AIE == 1 + * - UF == UIE == 1 + * Any time the IRQF bit is a 1, the !IRQ pin is driven low. + * All flag bits are cleared after Register C is read by the + * program or when the !RESET pin is low. + * + * * Valid RAM and Time (VRT) + * This bit indicates the condition of the battery connected + * to the VBAT pin. This bit is not writeable and should + * always be 1 when read. If a 0 is ever present, an + * exhausted internal lithium energy source is indicated and + * both the contents of the RTC data and RAM data are + * questionable. This bit is unaffected by !RESET. + * + * This file implements a generic version of the RTC/NVRAM chip, + * including the later update (DS12887A) which implemented a + * "century" register to be compatible with Y2K. + * + * Version: @(#)nvr_at.c 1.0.3 2018/03/11 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Mahod, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "machine/machine.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "mem.h" +#include "nmi.h" +#include "timer.h" +#include "device.h" +#include "nvr.h" +#include "rom.h" + + +/* RTC registers and bit definitions. */ +#define RTC_SECONDS 0 +#define RTC_ALSECONDS 1 +#define RTC_MINUTES 2 +#define RTC_ALMINUTES 3 +#define RTC_HOURS 4 +# define RTC_AMPM 0x80 /* PM flag if 12h format in use */ +#define RTC_ALHOURS 5 +#define RTC_DOW 6 +#define RTC_DOM 7 +#define RTC_MONTH 8 +#define RTC_YEAR 9 +#define RTC_REGA 10 +# define REGA_UIP 0x80 +# define REGA_DV2 0x40 +# define REGA_DV1 0x20 +# define REGA_DV0 0x10 +# define REGA_DV 0x70 +# define REGA_RS3 0x08 +# define REGA_RS2 0x04 +# define REGA_RS1 0x02 +# define REGA_RS0 0x01 +# define REGA_RS 0x0f +#define RTC_REGB 11 +# define REGB_SET 0x80 +# define REGB_PIE 0x40 +# define REGB_AIE 0x20 +# define REGB_UIE 0x10 +# define REGB_SQWE 0x08 +# define REGB_DM 0x04 +# define REGB_2412 0x02 +# define REGB_DSE 0x01 +#define RTC_REGC 12 +# define REGC_IRQF 0x80 +# define REGC_PF 0x40 +# define REGC_AF 0x20 +# define REGC_UF 0x10 +#define RTC_REGD 13 +# define REGD_VRT 0x80 +#define RTC_CENTURY 0x32 /* century register */ +#define RTC_REGS 14 /* number of registers */ + + +static nvr_t *nvrp; + + +/* Get the current NVR time. */ +static void +time_get(uint8_t *regs, struct tm *tm) +{ + int8_t temp; + + if (regs[RTC_REGB] & REGB_DM) { + /* NVR is in Binary data mode. */ + tm->tm_sec = regs[RTC_SECONDS]; + tm->tm_min = regs[RTC_MINUTES]; + temp = regs[RTC_HOURS]; + tm->tm_wday = (regs[RTC_DOW] - 1); + tm->tm_mday = regs[RTC_DOM]; + tm->tm_mon = (regs[RTC_MONTH] - 1); + tm->tm_year = regs[RTC_YEAR]; + tm->tm_year += (regs[RTC_CENTURY] * 100) - 1900; + } else { + /* NVR is in BCD data mode. */ + tm->tm_sec = RTC_DCB(regs[RTC_SECONDS]); + tm->tm_min = RTC_DCB(regs[RTC_MINUTES]); + temp = RTC_DCB(regs[RTC_HOURS]); + tm->tm_wday = (RTC_DCB(regs[RTC_DOW]) - 1); + tm->tm_mday = RTC_DCB(regs[RTC_DOM]); + tm->tm_mon = (RTC_DCB(regs[RTC_MONTH]) - 1); + tm->tm_year = RTC_DCB(regs[RTC_YEAR]); + tm->tm_year += (RTC_DCB(regs[RTC_CENTURY]) * 100) - 1900; + } + + /* Adjust for 12/24 hour mode. */ + if (regs[RTC_REGB] & REGB_2412) + tm->tm_hour = temp; + else + tm->tm_hour = ((temp & ~RTC_AMPM)%12) + ((temp&RTC_AMPM) ? 12 : 0); +} + + +/* Set the current NVR time. */ +static void +time_set(uint8_t *regs, struct tm *tm) +{ + int year = (tm->tm_year + 1900); + + if (regs[RTC_REGB] & REGB_DM) { + /* NVR is in Binary data mode. */ + regs[RTC_SECONDS] = tm->tm_sec; + regs[RTC_MINUTES] = tm->tm_min; + regs[RTC_DOW] = (tm->tm_wday + 1); + regs[RTC_DOM] = tm->tm_mday; + regs[RTC_MONTH] = (tm->tm_mon + 1); + regs[RTC_YEAR] = (year % 100); + regs[RTC_CENTURY] = (year / 100); + + if (regs[RTC_REGB] & REGB_2412) { + /* NVR is in 24h mode. */ + regs[RTC_HOURS] = tm->tm_hour; + } else { + /* NVR is in 12h mode. */ + regs[RTC_HOURS] = (tm->tm_hour % 12) ? (tm->tm_hour % 12) : 12; + if (tm->tm_hour > 11) + regs[RTC_HOURS] |= RTC_AMPM; + } + } else { + /* NVR is in BCD data mode. */ + regs[RTC_SECONDS] = RTC_BCD(tm->tm_sec); + regs[RTC_MINUTES] = RTC_BCD(tm->tm_min); + regs[RTC_DOW] = (RTC_BCD(tm->tm_wday) + 1); + regs[RTC_DOM] = RTC_BCD(tm->tm_mday); + regs[RTC_MONTH] = (RTC_BCD(tm->tm_mon) + 1); + regs[RTC_YEAR] = RTC_BCD(year % 100); + regs[RTC_CENTURY] = RTC_BCD(year / 100); + + if (regs[RTC_REGB] & REGB_2412) { + /* NVR is in 24h mode. */ + regs[RTC_HOURS] = RTC_BCD(tm->tm_hour); + } else { + /* NVR is in 12h mode. */ + regs[RTC_HOURS] = (tm->tm_hour % 12) + ? RTC_BCD(tm->tm_hour % 12) + : RTC_BCD(12); + if (tm->tm_hour > 11) + regs[RTC_HOURS] |= RTC_AMPM; + } + } +} + + +/* Check if the current time matches a set alarm time. */ +static int8_t +check_alarm(uint8_t *regs, int8_t addr) +{ +#define ALARM_DONTCARE 0xc0 + return((regs[addr+1] == regs[addr]) || + ((regs[addr+1] & ALARM_DONTCARE) == ALARM_DONTCARE)); +} + + +/* Update the NVR registers from the internal clock. */ +static void +update_timer(void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + struct tm tm; + + if (! (nvr->regs[RTC_REGB] & REGB_SET)) { + /* Get the current time from the internal clock. */ + nvr_time_get(&tm); + + /* Update registers with current time. */ + time_set(nvr->regs, &tm); + + /* Clear update status. */ + nvr->upd_stat = 0x00; + + /* Check for any alarms we need to handle. */ + if (check_alarm(nvr->regs, RTC_SECONDS) && + check_alarm(nvr->regs, RTC_MINUTES) && + check_alarm(nvr->regs, RTC_HOURS)) { + nvr->regs[RTC_REGC] |= REGC_AF; + if (nvr->regs[RTC_REGB] & REGB_AIE) { + nvr->regs[RTC_REGC] |= REGC_IRQF; + + /* Generate an interrupt. */ + if (nvr->irq != -1) + picint(1<irq); + } + } + + /* + * The flag and interrupt should be issued + * on update ended, not started. + */ + nvr->regs[RTC_REGC] |= REGC_UF; + if (nvr->regs[RTC_REGB] & REGB_UIE) { + nvr->regs[RTC_REGC] |= REGC_IRQF; + + /* Generate an interrupt. */ + if (nvr->irq != -1) + picint(1<irq); + } + } + + nvr->upd_ecount = 0; +} + + +/* Re-calculate the timer values. */ +static void +rtc_timer_recalc(nvr_t *nvr, int add) +{ + int64_t c, nt; + + c = 1 << ((nvr->regs[RTC_REGA] & REGA_RS) - 1); + nt = (int64_t)(RTCCONST * c * (1<rtctime += nt; + else if (nvr->rtctime > nt) + nvr->rtctime = nt; +} + + +static void +rtc_timer(void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + + if (! (nvr->regs[RTC_REGA] & REGA_RS)) { + nvr->rtctime = 0x7fffffff; + return; + } + + /* Update our timer interval. */ + rtc_timer_recalc(nvr, 1); + + nvr->regs[RTC_REGC] |= REGC_PF; + if (nvr->regs[RTC_REGB] & REGB_PIE) { + nvr->regs[RTC_REGC] |= REGC_IRQF; + + /* Generate an interrupt. */ + if (nvr->irq != -1) + picint(1<irq); + } +} + + +/* Callback from internal clock, another second passed. */ +static void +tick_timer(nvr_t *nvr) +{ + if (nvr->regs[RTC_REGB] & REGB_SET) return; + + nvr->upd_stat = REGA_UIP; + + nvr->upd_ecount = (int64_t)((244.0 + 1984.0) * TIMER_USEC); +} + + +/* Write to one of the NVR registers. */ +static void +nvr_write(uint16_t addr, uint8_t val, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + struct tm tm; + uint8_t old; + + cycles -= ISA_CYCLES(8); + + if (addr & 1) { + old = nvr->regs[nvr->addr]; + switch(nvr->addr) { + case RTC_REGA: + nvr->regs[RTC_REGA] = val; + if (val & REGA_RS) + rtc_timer_recalc(nvr, 1); + else + nvr->rtctime = 0x7fffffff; + break; + + case RTC_REGB: + nvr->regs[RTC_REGB] = val; + if (((old^val) & REGB_SET) && (val®B_SET)) { + /* According to the datasheet... */ + nvr->regs[RTC_REGA] &= ~REGA_UIP; + nvr->regs[RTC_REGB] &= ~REGB_UIE; + } + break; + + case RTC_REGC: /* R/O */ + case RTC_REGD: /* R/O */ + break; + + default: /* non-RTC registers are just NVRAM */ + if (nvr->regs[nvr->addr] != val) { + nvr->regs[nvr->addr] = val; + nvr_dosave = 1; + } + break; + } + + if ((nvr->addr < RTC_REGA) || (nvr->addr == RTC_CENTURY)) { + if ((nvr->addr != 1) && (nvr->addr != 3) && (nvr->addr != 5)) { + if ((old != val) && !enable_sync) { + /* Update internal clock. */ + time_get(nvr->regs, &tm); + nvr_time_set(&tm); + nvr_dosave = 1; + } + } + } + } else { + nvr->addr = (val & (nvr->size - 1)); + if (!(machines[machine].flags & MACHINE_MCA) && + (romset != ROM_IBMPS1_2133)) + nmi_mask = (~val & 0x80); + } +} + + +/* Read from one of the NVR registers. */ +static uint8_t +nvr_read(uint16_t addr, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t ret; + + cycles -= ISA_CYCLES(8); + + if (addr & 1) switch(nvr->addr) { + case RTC_REGA: + ret = (nvr->regs[RTC_REGA] & 0x7f) | nvr->upd_stat; + break; + + case RTC_REGC: + picintc(1<irq); + ret = nvr->regs[RTC_REGC]; + nvr->regs[RTC_REGC] = 0x00; + break; + + case RTC_REGD: + nvr->regs[RTC_REGD] |= REGD_VRT; + ret = nvr->regs[RTC_REGD]; + break; + + default: + ret = nvr->regs[nvr->addr]; + break; + } else { + ret = nvr->addr; + } + + return(ret); +} + + +/* Reset the RTC state to 1980/01/01 00:00. */ +static void +nvr_at_reset(nvr_t *nvr) +{ + memset(nvr->regs, 0x00, RTC_REGS); + nvr->regs[RTC_DOM] = 1; + nvr->regs[RTC_MONTH] = 1; + nvr->regs[RTC_YEAR] = RTC_BCD(80); + nvr->regs[RTC_CENTURY] = RTC_BCD(19); +} + + +/* Process after loading from file. */ +static void +nvr_at_start(nvr_t *nvr) +{ + struct tm tm; + + /* Initialize the internal and chip times. */ + if (enable_sync) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } + + /* Start the RTC. */ + nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1); + nvr->regs[RTC_REGB] = REGB_2412; + rtc_timer_recalc(nvr, 0); +} + + +void +nvr_at_init(int irq) +{ + nvr_t *nvr; + + /* Allocate an NVR for this machine. */ + nvr = (nvr_t *)malloc(sizeof(nvr_t)); + if (nvr == NULL) return; + memset(nvr, 0x00, sizeof(nvr_t)); + + /* This is machine specific. */ + nvr->size = machines[machine].nvrmask + 1; + nvr->irq = irq; + + /* Set up any local handlers here. */ + nvr->reset = nvr_at_reset; + nvr->start = nvr_at_start; + nvr->tick = tick_timer; + + /* Initialize the generic NVR. */ + nvr_init(nvr); + + /* Start the timers. */ + timer_add(update_timer, &nvr->upd_ecount, &nvr->upd_ecount, nvr); + timer_add(rtc_timer, &nvr->rtctime, TIMER_ALWAYS_ENABLED, nvr); + + /* Set up the I/O handler for this device. */ + io_sethandler(0x0070, 2, + nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); + + nvrp = nvr; +} + + +void +nvr_at_close(void) +{ + if (nvrp == NULL) return; + + if (nvrp->fn != NULL) + free(nvrp->fn); + + free(nvrp); + + nvrp = NULL; +} diff --git a/src/nvr_ps2.c b/src/nvr_ps2.c index 2fcd89d72..ce1cdfe2a 100644 --- a/src/nvr_ps2.c +++ b/src/nvr_ps2.c @@ -1,120 +1,168 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Handling of the PS/2 series CMOS devices. + * + * Version: @(#)nvr_ps2.c 1.0.4 2018/03/13 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ #include #include #include #include #include #include "86box.h" -#include "machine/machine.h" #include "cpu/cpu.h" +#include "machine/machine.h" #include "device.h" #include "io.h" #include "mem.h" -#include "rom.h" #include "nvr.h" #include "nvr_ps2.h" +#include "rom.h" -typedef struct ps2_nvr_t -{ - int addr; - uint8_t ram[8192]; +typedef struct { + int addr; + + uint8_t ram[8192]; } ps2_nvr_t; -static uint8_t ps2_nvr_read(uint16_t port, void *p) +static uint8_t +ps2_nvr_read(uint16_t port, void *priv) { - ps2_nvr_t *nvr = (ps2_nvr_t *)p; - - switch (port) - { - case 0x74: - return nvr->addr & 0xff; - case 0x75: - return nvr->addr >> 8; - case 0x76: - return nvr->ram[nvr->addr]; - } - - return 0xff; + ps2_nvr_t *nvr = (ps2_nvr_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x74: + ret = nvr->addr & 0xff; + break; + + case 0x75: + ret = nvr->addr >> 8; + break; + + case 0x76: + ret = nvr->ram[nvr->addr]; + break; + } + + return(ret); } -static void ps2_nvr_write(uint16_t port, uint8_t val, void *p) + +static void +ps2_nvr_write(uint16_t port, uint8_t val, void *priv) { - ps2_nvr_t *nvr = (ps2_nvr_t *)p; - - switch (port) - { - case 0x74: - nvr->addr = (nvr->addr & 0x1f00) | val; - break; - case 0x75: - nvr->addr = (nvr->addr & 0xff) | ((val & 0x1f) << 8); - break; - case 0x76: - nvr->ram[nvr->addr] = val; - break; - } + ps2_nvr_t *nvr = (ps2_nvr_t *)priv; + + switch (port) { + case 0x74: + nvr->addr = (nvr->addr & 0x1f00) | val; + break; + + case 0x75: + nvr->addr = (nvr->addr & 0xff) | ((val & 0x1f) << 8); + break; + + case 0x76: + nvr->ram[nvr->addr] = val; + break; + } } -static void *ps2_nvr_init(device_t *info) + +static void * +ps2_nvr_init(device_t *info) { - ps2_nvr_t *nvr = (ps2_nvr_t *)malloc(sizeof(ps2_nvr_t)); - FILE *f = NULL; + ps2_nvr_t *nvr; + FILE *f = NULL; - memset(nvr, 0, sizeof(ps2_nvr_t)); - - io_sethandler(0x0074, 0x0003, ps2_nvr_read, NULL, NULL, ps2_nvr_write, NULL, NULL, nvr); + nvr = (ps2_nvr_t *)malloc(sizeof(ps2_nvr_t)); + memset(nvr, 0x00, sizeof(ps2_nvr_t)); + + io_sethandler(0x0074, 3, + ps2_nvr_read,NULL,NULL, ps2_nvr_write,NULL,NULL, nvr); - switch (romset) - { - case ROM_IBMPS2_M70_TYPE3: f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"rb"); break; - case ROM_IBMPS2_M70_TYPE4: f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"rb"); break; - case ROM_IBMPS2_M80: f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"rb"); break; -#ifdef WALTJE - case ROM_IBMPS2_M80_486: f = nvr_fopen(L"ibmps2_m80-486_sec.nvr", L"rb"); break; -#endif - } - if (f) - { - fread(nvr->ram, 8192, 1, f); - fclose(f); - } - else - memset(nvr->ram, 0xFF, 8192); - - return nvr; + switch (romset) { + case ROM_IBMPS2_M80: + f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"rb"); + break; + } + + memset(nvr->ram, 0xff, 8192); + if (f != NULL) { + (void)fread(nvr->ram, 8192, 1, f); + fclose(f); + } + + return(nvr); } -void ps2_nvr_close(void *p) -{ - ps2_nvr_t *nvr = (ps2_nvr_t *)p; - FILE *f = NULL; - switch (romset) - { - case ROM_IBMPS2_M70_TYPE3: f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"wb"); break; - case ROM_IBMPS2_M70_TYPE4: f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"wb"); break; - case ROM_IBMPS2_M80: f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"wb"); break; -#ifdef WALTJE - case ROM_IBMPS2_M80_486: f = nvr_fopen(L"ibmps2_m80-486_sec.nvr", L"wb"); break; -#endif - } - if (f) - { - fwrite(nvr->ram, 8192, 1, f); - fclose(f); - } - - free(nvr); +static void +ps2_nvr_close(void *priv) +{ + ps2_nvr_t *nvr = (ps2_nvr_t *)priv; + FILE *f = NULL; + + switch (romset) { + case ROM_IBMPS2_M70_TYPE3: + f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"rb"); + break; + case ROM_IBMPS2_M70_TYPE4: + f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"rb"); + break; + case ROM_IBMPS2_M80: + f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"wb"); + break; + } + + if (f != NULL) { + (void)fwrite(nvr->ram, 8192, 1, f); + fclose(f); + } + + free(nvr->ram); + + free(nvr); } -device_t ps2_nvr_device = -{ - "PS/2 NVRRAM", - 0, - 0, - ps2_nvr_init, - ps2_nvr_close, - NULL, - NULL, NULL, NULL, NULL + +device_t ps2_nvr_device = { + "PS/2 Secondary NVRAM", + 0, 0, + ps2_nvr_init, ps2_nvr_close, NULL, + NULL, NULL, NULL, + NULL }; diff --git a/src/nvr_ps2.h b/src/nvr_ps2.h index 1656c82b0..802c27f4a 100644 --- a/src/nvr_ps2.h +++ b/src/nvr_ps2.h @@ -1 +1,44 @@ -extern device_t ps2_nvr_device; +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Definitions for the PS/2 cmos/nvr device. + * + * Version: @(#)nvr_ps2.h 1.0.1 2018/02/14 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef EMU_NVRPS2_H +# define EMU_NVRPS2_H + + +extern device_t ps2_nvr_device; + + +#endif /*EMU_NVRPS2_H*/ diff --git a/src/nvr_tc8521.c b/src/nvr_tc8521.c deleted file mode 100644 index 718221d84..000000000 --- a/src/nvr_tc8521.c +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "86box.h" -#include "mem.h" -#include "io.h" -#include "nvr.h" -#include "nvr_tc8521.h" -#include "rtc_tc8521.h" -#include "pic.h" -#include "pit.h" -#include "plat.h" -#include "rom.h" -#include "timer.h" -#include "config.h" -#include "nmi.h" -#include "machine/machine.h" - -int oldromset; -int nvrmask=63; -uint8_t nvrram[128]; -int nvraddr; - -int nvr_dosave = 0; - -static int64_t nvr_onesec_time = 0, nvr_onesec_cnt = 0; - -static void tc8521_onesec(void *p) -{ - nvr_onesec_cnt++; - if (nvr_onesec_cnt >= 100) - { - tc8521_tick(); - nvr_onesec_cnt = 0; - } - nvr_onesec_time += (int)(10000 * TIMER_USEC); -} - -void write_tc8521(uint16_t addr, uint8_t val, void *priv) -{ - uint8_t page = nvrram[0x0D] & 3; - - addr &= 0x0F; - if (addr < 0x0D) addr += 16 * page; - - if (addr >= 0x10 && nvrram[addr] != val) - nvr_dosave = 1; - - nvrram[addr] = val; -} - - -uint8_t read_tc8521(uint16_t addr, void *priv) -{ - uint8_t page = nvrram[0x0D] & 3; - - addr &= 0x0F; - if (addr < 0x0D) addr += 16 * page; - - return nvrram[addr]; -} - - -void tc8521_loadnvr() -{ - FILE *f; - - nvrmask=63; - oldromset=romset; - switch (romset) - { - case ROM_T1000: f = plat_fopen(nvr_path(L"t1000.nvr"), L"rb"); break; - case ROM_T1200: f = plat_fopen(nvr_path(L"t1200.nvr"), L"rb"); break; - default: return; - } - if (!f) - { - memset(nvrram,0xFF,64); - nvrram[0x0E] = 0; /* Test register */ - if (!enable_sync) - { - memset(nvrram, 0, 16); - } - return; - } - fread(nvrram,64,1,f); - if (enable_sync) - tc8521_internal_sync(nvrram); - else - tc8521_internal_set_nvrram(nvrram); /* Update the internal clock state based on the NVR registers. */ - fclose(f); -} - - -void tc8521_savenvr() -{ - FILE *f; - switch (oldromset) - { - case ROM_T1000: f = plat_fopen(nvr_path(L"t1000.nvr"), L"wb"); break; - case ROM_T1200: f = plat_fopen(nvr_path(L"t1200.nvr"), L"wb"); break; - default: return; - } - fwrite(nvrram,64,1,f); - fclose(f); -} - -void nvr_tc8521_init() -{ - io_sethandler(0x2C0, 0x10, read_tc8521, NULL, NULL, write_tc8521, NULL, NULL, NULL); - timer_add(tc8521_onesec, &nvr_onesec_time, TIMER_ALWAYS_ENABLED, NULL); -} diff --git a/src/nvr_tc8521.h b/src/nvr_tc8521.h deleted file mode 100644 index c17342bd6..000000000 --- a/src/nvr_tc8521.h +++ /dev/null @@ -1,12 +0,0 @@ -void nvr_tc8521_init(); - -extern int enable_sync; - -extern int nvr_dosave; - -void tc8521_loadnvr(); -void tc8521_savenvr(); - -void tc8521_nvr_recalc(); - -FILE *nvrfopen(char *fn, char *mode); diff --git a/src/pc.c b/src/pc.c index 224607f7d..3ecc85ab2 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.62 2018/03/06 + * Version: @(#)pc.c 1.0.63 2018/03/13 * * Authors: Sarah Walker, * Miran Grca, @@ -126,6 +126,7 @@ int cpu_manufacturer = 0, /* (C) cpu manufacturer */ cpu_use_dynarec = 0, /* (C) cpu uses/needs Dyna */ cpu = 3, /* (C) cpu type */ enable_external_fpu = 0; /* (C) enable external FPU */ +int enable_sync = 0; /* (C) enable time sync */ /* Statistics. */ @@ -500,8 +501,6 @@ pc_full_speed(void) setpitclock(14318184.0); } atfullspeed = 1; - - nvr_recalc(); } @@ -512,8 +511,6 @@ pc_speed_changed(void) setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); else setpitclock(14318184.0); - - nvr_recalc(); } diff --git a/src/rtc_tc8521.c b/src/rtc_tc8521.c deleted file mode 100644 index f3b64ba6a..000000000 --- a/src/rtc_tc8521.c +++ /dev/null @@ -1,221 +0,0 @@ -/* Emulation of: - Toshiba TC8521 Real Time Clock */ - -#include -#include -#include -#include -#include -#include "nvr.h" -#include "rtc_tc8521.h" - -#define peek2(a) (nvrram[(a##1)] + 10 * nvrram[(a##10)]) - -struct -{ - int sec; - int min; - int hour; - int mday; - int mon; - int year; -} internal_clock; - -/* Table for days in each month */ -static int rtc_days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -/* Called to determine whether the year is leap or not */ -static int rtc_is_leap(int org_year) -{ - if (org_year % 400 == 0) return 1; - if (org_year % 100 == 0) return 0; - if (org_year % 4 == 0) return 1; - return 0; -} - -/* Called to determine the days in the current month */ -static int rtc_get_days(int org_month, int org_year) -{ - if (org_month != 2) - return rtc_days_in_month[org_month]; - else - return rtc_is_leap(org_year) ? 29 : 28; -} - -/* Called when the internal clock gets updated */ -static void tc8521_recalc() -{ - if (internal_clock.sec == 60) - { - internal_clock.sec = 0; - internal_clock.min++; - } - if (internal_clock.min == 60) - { - internal_clock.min = 0; - internal_clock.hour++; - } - if (internal_clock.hour == 24) - { - internal_clock.hour = 0; - internal_clock.mday++; - } - if (internal_clock.mday == (rtc_get_days(internal_clock.mon, internal_clock.year) + 1)) - { - internal_clock.mday = 1; - internal_clock.mon++; - } - if (internal_clock.mon == 13) - { - internal_clock.mon = 1; - internal_clock.year++; - } -} - -/* Called when ticking the second */ -void tc8521_tick() -{ - internal_clock.sec++; - tc8521_recalc(); -} - -/* Called when modifying the NVR registers */ -void tc8521_update(uint8_t *nvrram, int reg) -{ - int temp; - - switch(reg) - { - case TC8521_SECOND1: - case TC8521_SECOND10: - internal_clock.sec = peek2(TC8521_SECOND); - break; - case TC8521_MINUTE1: - case TC8521_MINUTE10: - internal_clock.min = peek2(TC8521_MINUTE); - break; - case TC8521_HOUR1: - case TC8521_HOUR10: - temp = peek2(TC8521_HOUR); - if (nvrram[TC8521_24HR] & 1) - internal_clock.hour = temp; - else - internal_clock.hour = ((temp & ~0x20) % 12) + ((temp & 0x20) ? 12 : 0); - break; - case TC8521_DAY1: - case TC8521_DAY10: - internal_clock.mday = peek2(TC8521_DAY); - break; - case TC8521_MONTH1: - case TC8521_MONTH10: - internal_clock.mon = peek2(TC8521_MONTH); - break; - case TC8521_YEAR1: - case TC8521_YEAR10: - internal_clock.year = 1980 + peek2(TC8521_YEAR); - break; - } -} - -/* Called to obtain the current day of the week based on the internal clock */ -static int time_week_day() -{ - int day_of_month = internal_clock.mday; - int month2 = internal_clock.mon; - int year2 = internal_clock.year % 100; - int century = ((internal_clock.year - year2) / 100) % 4; - int sum = day_of_month + month2 + year2 + century; - /* (Sum mod 7) gives 0 for Saturday, we need it for Sunday, so +6 for Saturday to get 6 and Sunday 0 */ - int raw_wd = ((sum + 6) % 7); - return raw_wd; -} - -/* Called to get time into the internal clock */ -static void tc8521_internal_get(struct tm *time_var) -{ - time_var->tm_sec = internal_clock.sec; - time_var->tm_min = internal_clock.min; - time_var->tm_hour = internal_clock.hour; - time_var->tm_wday = time_week_day(); - time_var->tm_mday = internal_clock.mday; - time_var->tm_mon = internal_clock.mon - 1; - time_var->tm_year = internal_clock.year - 1900; -} - -static void tc8521_internal_set(struct tm *time_var) -{ - internal_clock.sec = time_var->tm_sec; - internal_clock.min = time_var->tm_min; - internal_clock.hour = time_var->tm_hour; - internal_clock.mday = time_var->tm_mday; - internal_clock.mon = time_var->tm_mon + 1; - internal_clock.year = time_var->tm_year + 1900; -} - -static void tc8521_set_nvrram(uint8_t *nvrram, struct tm *cur_time_tm) -{ - nvrram[TC8521_SECOND1] = cur_time_tm->tm_sec % 10; - nvrram[TC8521_SECOND10] = cur_time_tm->tm_sec / 10; - nvrram[TC8521_MINUTE1] = cur_time_tm->tm_min % 10; - nvrram[TC8521_MINUTE10] = cur_time_tm->tm_min / 10; - if (nvrram[TC8521_24HR] & 1) - { - nvrram[TC8521_HOUR1] = cur_time_tm->tm_hour % 10; - nvrram[TC8521_HOUR10] = cur_time_tm->tm_hour / 10; - } - else - { - nvrram[TC8521_HOUR1] = (cur_time_tm->tm_hour % 12) % 10; - nvrram[TC8521_HOUR10] = ((cur_time_tm->tm_hour % 12) / 10) - | (cur_time_tm->tm_hour >= 12) ? 2 : 0; - } - nvrram[TC8521_WEEKDAY] = cur_time_tm->tm_wday; - nvrram[TC8521_DAY1] = cur_time_tm->tm_mday % 10; - nvrram[TC8521_DAY10] = cur_time_tm->tm_mday / 10; - nvrram[TC8521_MONTH1] = (cur_time_tm->tm_mon + 1) / 10; - nvrram[TC8521_MONTH10] = (cur_time_tm->tm_mon + 1) % 10; - nvrram[TC8521_YEAR1] = (cur_time_tm->tm_year - 80) % 10; - nvrram[TC8521_YEAR10] = ((cur_time_tm->tm_year - 80) % 100) / 10; -} - - -void tc8521_internal_set_nvrram(uint8_t *nvrram) -{ - /* Load the entire internal clock state from the NVR. */ - internal_clock.sec = peek2(TC8521_SECOND); - internal_clock.min = peek2(TC8521_MINUTE); - if (nvrram[TC8521_24HR] & 1) - { - internal_clock.hour = peek2(TC8521_HOUR); - } - else - { - internal_clock.hour = (peek2(TC8521_HOUR) % 12) - + (nvrram[TC8521_HOUR10] & 2) ? 12 : 0; - } - internal_clock.mday = peek2(TC8521_DAY); - internal_clock.mon = peek2(TC8521_MONTH); - internal_clock.year = 1980 + peek2(TC8521_YEAR); -} - -void tc8521_internal_sync(uint8_t *nvrram) -{ - struct tm *cur_time_tm; - time_t cur_time; - - time(&cur_time); - cur_time_tm = localtime(&cur_time); - - tc8521_internal_set(cur_time_tm); - - tc8521_set_nvrram(nvrram, cur_time_tm); -} - -void tc8521_get(uint8_t *nvrram) -{ - struct tm cur_time_tm; - - tc8521_internal_get(&cur_time_tm); - - tc8521_set_nvrram(nvrram, &cur_time_tm); -} diff --git a/src/rtc_tc8521.h b/src/rtc_tc8521.h deleted file mode 100644 index 61c822af2..000000000 --- a/src/rtc_tc8521.h +++ /dev/null @@ -1,33 +0,0 @@ - -/* The TC8521 is a 4-bit RTC, so each memory location can only hold a single - * BCD digit. Hence everything has 'ones' and 'tens' digits. */ -enum TC8521_ADDR -{ - /* Page 0 registers */ - TC8521_SECOND1, - TC8521_SECOND10, - TC8521_MINUTE1, - TC8521_MINUTE10, - TC8521_HOUR1, - TC8521_HOUR10, - TC8521_WEEKDAY, - TC8521_DAY1, - TC8521_DAY10, - TC8521_MONTH1, - TC8521_MONTH10, - TC8521_YEAR1, - TC8521_YEAR10, - TC8521_PAGE, /* PAGE register */ - TC8521_TEST, /* TEST register */ - TC8521_RESET, /* RESET register */ - /* Page 1 registers */ - TC8521_24HR = 0x1A, - TC8521_LEAPYEAR = 0x1B -}; - - -void tc8521_tick(); -void tc8521_update(uint8_t *nvrram, int reg); -void tc8521_get(uint8_t *nvrram); -void tc8521_internal_set_nvrram(uint8_t *nvrram); -void tc8521_internal_sync(uint8_t *nvrram); diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 81e2fbd64..b5932d0e4 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.110 2018/03/07 +# Version: @(#)Makefile.mingw 1.0.111 2018/03/13 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -415,8 +415,7 @@ CFLAGS := $(CFLAGS) ######################################################################### MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \ pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \ - device.o nvr.o nvr_tc8521.o rtc_tc8521.o nvr_at.o \ - nvr_ps2.o $(VNCOBJ) $(RDPOBJ) + device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) INTELOBJ := intel.o \ intel_flash.o \ @@ -429,7 +428,8 @@ CPUOBJ := cpu.o cpu_table.o \ MCHOBJ := machine.o machine_table.o \ m_xt.o m_xt_compaq.o \ - m_xt_t1000.o m_xt_xi8088.o \ + m_xt_t1000.o m_xt_t1000_vid.o \ + m_xt_xi8088.o \ m_pcjr.o \ m_amstrad.o \ m_europc.o m_europc_hdc.o \ @@ -437,7 +437,7 @@ MCHOBJ := machine.o machine_table.o \ m_at.o \ m_at_ali1429.o m_at_commodore.o \ m_at_neat.o m_at_headland.o \ - m_at_t3100e.o \ + m_at_t3100e.o m_at_t3100e_vid.o \ m_ps1.o \ m_ps2_isa.o m_ps2_mca.o \ m_at_opti495.o m_at_scat.o \ @@ -526,7 +526,6 @@ VIDOBJ := video.o \ vid_hercules.o vid_herculesplus.o vid_incolor.o \ vid_colorplus.o \ vid_genius.o \ - vid_t1000.o vid_t3100e.o \ vid_wy700.o \ vid_ega.o vid_ega_render.o \ vid_svga.o vid_svga_render.o \ From b35e6a535dc1d6d8df49512647c7847c0e90995d Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 14 Mar 2018 04:17:16 +0100 Subject: [PATCH 10/23] Fixed the SMC FDC37C932FR's GPIO port change handler. --- src/sio_fdc37c93x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sio_fdc37c93x.c b/src/sio_fdc37c93x.c index ae8206b6a..0d4076ade 100644 --- a/src/sio_fdc37c93x.c +++ b/src/sio_fdc37c93x.c @@ -9,7 +9,7 @@ * Implementation of the SMC FDC37C932FR and FDC37C935 Super * I/O Chips. * - * Version: @(#)sio_fdc37c93x.c 1.0.10 2018/01/16 + * Version: @(#)sio_fdc37c93x.c 1.0.11 2018/03/14 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -36,7 +36,7 @@ static int fdc37c93x_curreg = 0; static int fdc37c93x_gpio_reg = 0; static uint8_t fdc37c93x_regs[48]; static uint8_t fdc37c93x_ld_regs[10][256]; -static uint8_t fdc37c93x_gpio_base = 0x00EA; +static uint16_t fdc37c93x_gpio_base = 0x00EA; static fdc_t *fdc37c93x_fdc; static uint8_t tries; @@ -122,12 +122,12 @@ static void fdc37c93x_auxio_handler(void) { uint16_t ld_port = 0; - uint8_t local_enable = !!fdc37c93x_ld_regs[3][0x30]; + uint8_t local_enable = !!fdc37c93x_ld_regs[8][0x30]; io_removehandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); if (local_enable) { - fdc37c93x_gpio_base = ld_port = make_port(3); + fdc37c93x_gpio_base = ld_port = make_port(8); /* pclog("fdc37c93x: Setting Auxiliary I/O port to %04X\n", ld_port); */ if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) io_sethandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); @@ -377,7 +377,7 @@ process_value: } break; case 8: - /* Serial port 2 */ + /* Auxiliary I/O */ switch(fdc37c93x_curreg) { case 0x30: From a9c5ba13453f35cf68550eea69cc968a809f3f5c Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 15 Mar 2018 00:02:19 +0100 Subject: [PATCH 11/23] Rewrote the 86F handler's turbo mode sector present checking, reduces the emulator's RAM usage by about 330 MB. --- src/floppy/fdd.c | 5 ++- src/floppy/fdd.h | 2 +- src/floppy/fdd_86f.c | 97 +++++++++++++++++++++++++++++++++---------- src/floppy/fdd_86f.h | 6 ++- src/floppy/fdd_imd.c | 6 +-- src/floppy/fdd_img.c | 6 +-- src/floppy/fdd_json.c | 6 +-- src/floppy/fdd_td0.c | 6 +-- 8 files changed, 97 insertions(+), 37 deletions(-) diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 4c048e93a..a309e7e3a 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -8,7 +8,7 @@ * * Implementation of the floppy drive emulation. * - * Version: @(#)fdd.c 1.0.8 2018/03/06 + * Version: @(#)fdd.c 1.0.9 2018/03/14 * * Authors: Sarah Walker, * Miran Grca, @@ -447,6 +447,7 @@ void fdd_load(int drive, wchar_t *fn) { driveloaders[drive] = c; memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2); + d86f_initialize_linked_lists(drive); loaders[c].load(drive, floppyfns[drive]); drive_empty[drive] = 0; fdd_forced_seek(drive, 0); @@ -468,6 +469,8 @@ void fdd_close(int drive) drive_empty[drive] = 1; fdd_set_head(drive, 0); floppyfns[drive][0] = 0; + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); drives[drive].hole = NULL; drives[drive].poll = NULL; drives[drive].seek = NULL; diff --git a/src/floppy/fdd.h b/src/floppy/fdd.h index 8b05881ef..f4a26e988 100644 --- a/src/floppy/fdd.h +++ b/src/floppy/fdd.h @@ -263,7 +263,7 @@ typedef union void d86f_set_version(int drive, uint16_t version); void d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n); -void d86f_zero_bit_field(int drive, int side); +void d86f_destroy_linked_lists(int drive, int side); void d86f_set_fdc(void *fdc); void fdi_set_fdc(void *fdc); diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index a36b79e29..3d5064a80 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -10,7 +10,7 @@ * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * Version: @(#)fdd_86f.c 1.0.15 2018/03/05 + * Version: @(#)fdd_86f.c 1.0.16 2018/03/14 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -195,6 +195,14 @@ typedef union { static fdc_t *d86f_fdc; +#pragma pack(push,1) +typedef struct +{ + uint8_t c, h, r, n; + void *prev; +} sector_t; +#pragma pack(pop) + #pragma pack(push,1) struct { @@ -239,7 +247,7 @@ struct uint8_t *outbuf; uint32_t dma_over; int turbo_pos; - uint16_t sector_id_bit_field[2][256][256][256]; + sector_t *last_side_sector[2]; } d86f[FDD_NUM + 1]; #pragma pack(pop) @@ -265,25 +273,29 @@ d86f_log(const char *format, ...) } -void d86f_zero_bit_field(int drive, int side) +void d86f_initialize_linked_lists(int drive) { - int i = 0; - int j = 0; - int k = 0; - int l = 0; + d86f[drive].last_side_sector[0] = NULL; + d86f[drive].last_side_sector[1] = NULL; +} - for (i = 0; i < side; i++) +void d86f_destroy_linked_lists(int drive, int side) +{ + sector_t *s; + sector_t *t; + + if (d86f[drive].last_side_sector[side]) { - for (j = 0; j < 256; j++) - { - for (k = 0; k < 256; k++) - { - for (l = 0; l < 256; l++) - { - d86f[drive].sector_id_bit_field[i][j][k][l] = 0; - } - } + s = d86f[drive].last_side_sector[side]; + while (s) { + t = s->prev; + free(s); + s = NULL; + if (!t) + break; + s = t; } + d86f[drive].last_side_sector[side] = NULL; } } @@ -2190,6 +2202,24 @@ void d86f_turbo_format(int drive, int side, int nop) } } +int d86f_sector_is_present(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + sector_t *s, *t; + + if (d86f[drive].last_side_sector[side]) { + s = d86f[drive].last_side_sector[side]; + while (s) { + if ((s->c == c) && (s->h == h) && (s->r == r) && (s->n == n)) + return 1; + if (!s->prev) + break; + t = s->prev; + s = t; + } + } + return 0; +} + void d86f_turbo_poll(int drive, int side) { if ((d86f[drive].state != STATE_IDLE) && (d86f[drive].state != STATE_SECTOR_NOT_FOUND) && ((d86f[drive].state & 0xF8) != 0xE8)) @@ -2213,7 +2243,11 @@ void d86f_turbo_poll(int drive, int side) d86f[drive].state++; return; case STATE_02_FIND_ID: - if (!(d86f[drive].sector_id_bit_field[side][fdc_get_read_track_sector(d86f_fdc).id.c][fdc_get_read_track_sector(d86f_fdc).id.h][fdc_get_read_track_sector(d86f_fdc).id.r] & (1 << fdc_get_read_track_sector(d86f_fdc).id.n))) + if (!d86f_sector_is_present(drive, side, + fdc_get_read_track_sector(d86f_fdc).id.c, + fdc_get_read_track_sector(d86f_fdc).id.h, + fdc_get_read_track_sector(d86f_fdc).id.r, + fdc_get_read_track_sector(d86f_fdc).id.n)) { d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = d86f[drive].error_condition = 0; fdc_nosector(d86f_fdc); @@ -2234,7 +2268,11 @@ void d86f_turbo_poll(int drive, int side) case STATE_0C_FIND_ID: case STATE_11_FIND_ID: case STATE_16_FIND_ID: - if (!(d86f[drive].sector_id_bit_field[side][d86f[drive].req_sector.id.c][d86f[drive].req_sector.id.h][d86f[drive].req_sector.id.r] & (1 << d86f[drive].req_sector.id.n))) + if (!d86f_sector_is_present(drive, side, + d86f[drive].req_sector.id.c, + d86f[drive].req_sector.id.h, + d86f[drive].req_sector.id.r, + d86f[drive].req_sector.id.n)) { d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = d86f[drive].error_condition = 0; fdc_nosector(d86f_fdc); @@ -2577,6 +2615,8 @@ uint16_t d86f_prepare_pretrack(int drive, int side, int iso) d86f[drive].index_hole_pos[side] = 0; + d86f_destroy_linked_lists(drive, side); + for (i = 0; i < raw_size; i++) { d86f_write_direct_common(drive, side, gap_fill, 0, i); @@ -2621,6 +2661,7 @@ uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint16_t pos; int i; + sector_t *s; int real_gap2_len = gap2; int real_gap3_len = gap3; @@ -2635,7 +2676,15 @@ uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint16_t dataam_mfm = 0x4555; uint16_t datadam_mfm = 0x4A55; - d86f[drive].sector_id_bit_field[side][id_buf[0]][id_buf[1]][id_buf[2]] |= (1 << id_buf[3]); + s = (sector_t *) malloc(sizeof(sector_t)); + memset(s, 0, sizeof(sector_t)); + s->c = id_buf[0]; + s->h = id_buf[1]; + s->r = id_buf[2]; + s->n = id_buf[3]; + if (d86f[drive].last_side_sector[side]) + s->prev = d86f[drive].last_side_sector[side]; + d86f[drive].last_side_sector[side] = s; mfm = d86f_is_mfm(drive); @@ -3748,10 +3797,16 @@ void d86f_load(int drive, wchar_t *fn) void d86f_init() { + int i; + memset(d86f, 0, sizeof(d86f)); d86f_setupcrc(0x1021); - d86f[0].state = d86f[1].state = STATE_IDLE; + for (i = 0; i < (FDD_NUM + 1); i++) + { + d86f[i].state = STATE_IDLE; + d86f_initialize_linked_lists(i); + } } void d86f_set_fdc(void *fdc) diff --git a/src/floppy/fdd_86f.h b/src/floppy/fdd_86f.h index 983915fcb..f272ff59b 100644 --- a/src/floppy/fdd_86f.h +++ b/src/floppy/fdd_86f.h @@ -10,7 +10,7 @@ * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * Version: @(#)floppy_86f.h 1.0.4 2018/01/18 + * Version: @(#)floppy_86f.h 1.0.5 2018/03/14 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -69,7 +69,9 @@ extern int gap4_size[2]; #define D86FVER 0x020B extern void d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n); -extern void d86f_zero_bit_field(int drive, int side); + +extern void d86f_initialize_linked_lists(int drive); +extern void d86f_destroy_linked_lists(int drive, int side); #endif /*EMU_FLOPPY_86F_H*/ diff --git a/src/floppy/fdd_imd.c b/src/floppy/fdd_imd.c index ca56f5fe7..503521e1d 100644 --- a/src/floppy/fdd_imd.c +++ b/src/floppy/fdd_imd.c @@ -8,7 +8,7 @@ * * Implementation of the IMD floppy image format. * - * Version: @(#)fdd_imd.c 1.0.7 2018/03/06 + * Version: @(#)fdd_imd.c 1.0.8 2018/03/14 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -542,8 +542,8 @@ void imd_seek(int drive, int track) d86f_reset_index_hole_pos(drive, 0); d86f_reset_index_hole_pos(drive, 1); - d86f_zero_bit_field(drive, 0); - d86f_zero_bit_field(drive, 1); + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); if (track > imd[drive].track_count) { diff --git a/src/floppy/fdd_img.c b/src/floppy/fdd_img.c index 23ac2d919..daab0ad39 100644 --- a/src/floppy/fdd_img.c +++ b/src/floppy/fdd_img.c @@ -9,7 +9,7 @@ * Implementation of the raw sector-based floppy image format, * as well as the Japanese FDI, CopyQM, and FDF formats. * - * Version: @(#)fdd_img.c 1.0.8 2018/01/16 + * Version: @(#)fdd_img.c 1.0.9 2018/03/14 * * Authors: Sarah Walker, * Miran Grca, @@ -960,8 +960,8 @@ void img_seek(int drive, int track) d86f_reset_index_hole_pos(drive, 0); d86f_reset_index_hole_pos(drive, 1); - d86f_zero_bit_field(drive, 0); - d86f_zero_bit_field(drive, 1); + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); if (track > img[drive].tracks) { diff --git a/src/floppy/fdd_json.c b/src/floppy/fdd_json.c index 8bf8cc6c4..1daad4ee8 100644 --- a/src/floppy/fdd_json.c +++ b/src/floppy/fdd_json.c @@ -8,7 +8,7 @@ * * Implementation of the PCjs JSON floppy image format. * - * Version: @(#)fdd_json.c 1.0.10 2018/01/16 + * Version: @(#)fdd_json.c 1.0.11 2018/03/14 * * Author: Fred N. van Kempen, * @@ -357,8 +357,8 @@ json_seek(int drive, int track) /* Reset the 86F state machine. */ d86f_reset_index_hole_pos(drive, 0); d86f_reset_index_hole_pos(drive, 1); - d86f_zero_bit_field(drive, 0); - d86f_zero_bit_field(drive, 1); + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); interleave_type = 0; diff --git a/src/floppy/fdd_td0.c b/src/floppy/fdd_td0.c index 20e1a019c..c3056f705 100644 --- a/src/floppy/fdd_td0.c +++ b/src/floppy/fdd_td0.c @@ -8,7 +8,7 @@ * * Implementation of the Teledisk floppy image format. * - * Version: @(#)fdd_td0.c 1.0.7 2018/01/16 + * Version: @(#)fdd_td0.c 1.0.8 2018/03/14 * * Authors: Milodrag Milanovic, * Haruhiko OKUMURA, @@ -1111,8 +1111,8 @@ void td0_seek(int drive, int track) d86f_reset_index_hole_pos(drive, 0); d86f_reset_index_hole_pos(drive, 1); - d86f_zero_bit_field(drive, 0); - d86f_zero_bit_field(drive, 1); + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); if (track > td0[drive].tracks) { From a51bcfc77dfa08f8c1691d93de9c0f9ef16792ff Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 15 Mar 2018 00:25:59 +0100 Subject: [PATCH 12/23] The sector presence linked lists are no longer allocated for floppy drives not in turbo mode. --- src/floppy/fdd_86f.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index 3d5064a80..4c8f6c600 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -10,7 +10,7 @@ * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * Version: @(#)fdd_86f.c 1.0.16 2018/03/14 + * Version: @(#)fdd_86f.c 1.0.17 2018/03/14 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -2676,15 +2676,17 @@ uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint16_t dataam_mfm = 0x4555; uint16_t datadam_mfm = 0x4A55; - s = (sector_t *) malloc(sizeof(sector_t)); - memset(s, 0, sizeof(sector_t)); - s->c = id_buf[0]; - s->h = id_buf[1]; - s->r = id_buf[2]; - s->n = id_buf[3]; - if (d86f[drive].last_side_sector[side]) - s->prev = d86f[drive].last_side_sector[side]; - d86f[drive].last_side_sector[side] = s; + if (fdd_get_turbo(drive) && (d86f[drive].version == 0x0063)) { + s = (sector_t *) malloc(sizeof(sector_t)); + memset(s, 0, sizeof(sector_t)); + s->c = id_buf[0]; + s->h = id_buf[1]; + s->r = id_buf[2]; + s->n = id_buf[3]; + if (d86f[drive].last_side_sector[side]) + s->prev = d86f[drive].last_side_sector[side]; + d86f[drive].last_side_sector[side] = s; + } mfm = d86f_is_mfm(drive); From 47d2ff142dc143cd151dcddfeae6284c10eb5edd Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 15 Mar 2018 20:32:34 +0100 Subject: [PATCH 13/23] Reworked the cursor emulation of the Cirrus cards and added additional fixes to make the OS/2 SVGA detection happy. Added a GD5426-based Diamond SpeedStar Pro card to the table. --- src/video/vid_cl54xx.c | 380 +++++++++++++++++++++++------------------ src/video/vid_cl54xx.h | 1 + src/video/vid_table.c | 1 + src/video/video.h | 5 +- 4 files changed, 222 insertions(+), 165 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index d53a8404f..09e70bbe6 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -7,9 +7,9 @@ * This file is part of the 86Box distribution. * * Emulation of select Cirrus Logic cards (CL-GD 5428, - * CL-GD 5429, 5430, 5434 and 5436 are supported). + * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). * - * Version: @(#)vid_cl_54xx.c 1.0.11 2018/03/08 + * Version: @(#)vid_cl_54xx.c 1.0.9 2018/03/02 * * Authors: Sarah Walker, * Barry Rodewald, @@ -40,8 +40,8 @@ #include "vid_cl54xx.h" #define BIOS_GD5424_PATH L"roms/video/cirruslogic/cl5424.bin" -#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.bin" -#define BIOS_GD5428_VLB_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB (Cirrus Logic 5428)_v3.04.bin" +#define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" +#define BIOS_GD5428_PATH L"roms/video/cirruslogic/vlbusjapan.BIN" #define BIOS_GD5429_PATH L"roms/video/cirruslogic/5429.vbi" #define BIOS_GD5430_VLB_PATH L"roms/video/cirruslogic/diamondvlbus.bin" #define BIOS_GD5430_PCI_PATH L"roms/video/cirruslogic/pci.bin" @@ -49,6 +49,7 @@ #define BIOS_GD5436_PATH L"roms/video/cirruslogic/5436.vbi" #define CIRRUS_ID_CLGD5424 0x94 +#define CIRRUS_ID_CLGD5426 0x90 #define CIRRUS_ID_CLGD5428 0x98 #define CIRRUS_ID_CLGD5429 0x9c #define CIRRUS_ID_CLGD5430 0xa0 @@ -77,9 +78,13 @@ #define CIRRUS_BUSTYPE_VLBSLOW 0x30 #define CIRRUS_BUSTYPE_ISA 0x38 #define CIRRUS_MMIO_ENABLE 0x04 -#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared. +#define CIRRUS_MMIO_USE_PCIADDR 0x40 /* 0xb8000 if cleared. */ #define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 +// control 0x0b +#define CIRRUS_BANKING_DUAL 0x01 +#define CIRRUS_BANKING_GRANULARITY_16K 0x20 /* set:16k, clear:4k */ + /* control 0x30 */ #define CIRRUS_BLTMODE_BACKWARDS 0x01 #define CIRRUS_BLTMODE_MEMSYSDEST 0x02 @@ -93,6 +98,13 @@ #define CIRRUS_BLTMODE_PIXELWIDTH24 0x20 #define CIRRUS_BLTMODE_PIXELWIDTH32 0x30 +// control 0x31 +#define CIRRUS_BLT_BUSY 0x01 +#define CIRRUS_BLT_START 0x02 +#define CIRRUS_BLT_RESET 0x04 +#define CIRRUS_BLT_FIFOUSED 0x10 +#define CIRRUS_BLT_AUTOSTART 0x80 + // control 0x33 #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 #define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 @@ -134,7 +146,7 @@ typedef struct gd54xx_t uint32_t dst_addr, src_addr; uint8_t mask, mode, rop; uint8_t modeext; - uint8_t bltstart; + uint8_t status; uint16_t trans_col, trans_mask; uint32_t dst_addr_backup, src_addr_backup; @@ -199,7 +211,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if (svga->seqaddr > 5) { svga->seqregs[svga->seqaddr & 0x1f] = val; switch (svga->seqaddr & 0x1f) { - case 6: /* cirrus unlock extensions */ + case 6: val &= 0x17; if (val == 0x12) svga->seqregs[6] = 0x12; @@ -214,22 +226,30 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) break; case 0x10: case 0x30: case 0x50: case 0x70: case 0x90: case 0xb0: case 0xd0: case 0xf0: - svga->hwcursor.x = (val << 3) | ((svga->seqaddr >> 5) & 7); + svga->hwcursor.x = (val << 3) | (svga->seqaddr >> 5); break; case 0x11: case 0x31: case 0x51: case 0x71: case 0x91: case 0xb1: case 0xd1: case 0xf1: - svga->hwcursor.y = (val << 3) | ((svga->seqaddr >> 5) & 7); + svga->hwcursor.y = (val << 3) | (svga->seqaddr >> 5); break; case 0x12: - svga->hwcursor.ena = val & 1; + svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; + svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; + svga->hwcursor.yoff = 0; + if (val & CIRRUS_CURSOR_LARGE) + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); + else + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); break; case 0x13: - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3f) * 256)); + if (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3c) * 256)); + else + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3f) * 256)); break; case 0x07: svga->set_reset_disabled = svga->seqregs[7] & 1; case 0x17: - /* svga->seqregs[0x17] = (svga->seqregs[0x17] & 0x38) | (val & 0xc7); */ gd543x_recalc_mapping(gd54xx); break; } @@ -394,8 +414,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) val = (svga->crtc[7] & ~0x10) | (val & 0x10); old = svga->crtc[svga->crtcreg]; - if ((svga->crtcreg != 0x27) && (svga->crtcreg != 0x28)) - svga->crtc[svga->crtcreg] = val; + svga->crtc[svga->crtcreg] = val; if (old != val) { if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { @@ -421,18 +440,31 @@ gd54xx_in(uint16_t addr, void *p) addr ^= 0x60; switch (addr) { + case 0x3c4: + if ((svga->seqregs[6] & 0x17) == 0x12) + { + temp = svga->seqaddr; + if ((temp & 0x1e) == 0x10) + { + if (temp & 1) + temp = ((svga->hwcursor.y & 7) << 5) | 0x11; + else + temp = ((svga->hwcursor.x & 7) << 5) | 0x10; + } + return temp; + } + return svga->seqaddr; + case 0x3c5: if (svga->seqaddr > 5) { switch (svga->seqaddr) { case 6: - return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; + return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; case 0x0b: case 0x0c: case 0x0d: case 0x0e: - return gd54xx->vclk_n[svga->seqaddr-0x0b]; - case 0x0f: - return svga->seqregs[0x0f]; + return gd54xx->vclk_n[svga->seqaddr-0x0b]; case 0x17: temp = svga->gdcreg[0x17] & ~(7 << 3); - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5430) { + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { if (gd54xx->vlb) temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); else @@ -448,8 +480,6 @@ gd54xx_in(uint16_t addr, void *p) return temp; case 0x1b: case 0x1c: case 0x1d: case 0x1e: return gd54xx->vclk_d[svga->seqaddr-0x1b]; - case 0x1f: - return svga->seqregs[0x1f]; } return svga->seqregs[svga->seqaddr & 0x3f]; } @@ -473,7 +503,7 @@ gd54xx_in(uint16_t addr, void *p) case 0x24: /*Attribute controller toggle readback (R)*/ return svga->attrff << 7; case 0x26: /*Attribute controller index readback (R)*/ - return svga->attraddr & 0x3f; + return svga->attraddr & 0x3f; case 0x27: /*ID*/ return svga->crtc[0x27]; /*GD542x/GD543x*/ case 0x28: /*Class ID*/ @@ -492,13 +522,13 @@ gd54xx_recalc_banking(gd54xx_t *gd54xx) { svga_t *svga = &gd54xx->svga; - if (svga->gdcreg[0xb] & 0x20) + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) gd54xx->bank[0] = svga->gdcreg[0x09] << 14; else gd54xx->bank[0] = svga->gdcreg[0x09] << 12; - if (svga->gdcreg[0xb] & 0x01) { - if (svga->gdcreg[0xb] & 0x20) + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) gd54xx->bank[1] = svga->gdcreg[0x0a] << 14; else gd54xx->bank[1] = svga->gdcreg[0x0a] << 12; @@ -523,7 +553,7 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) if (!(svga->seqregs[7] & 0xf0)) { mem_mapping_disable(&gd54xx->linear_mapping); - switch (svga->gdcreg[6] & 0x0C) { + switch (svga->gdcreg[6] & 0x0c) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; @@ -534,12 +564,10 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) break; case 0x8: /*32k at B0000*/ mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); - mem_mapping_disable(&gd54xx->mmio_mapping); svga->banked_mask = 0x7fff; break; case 0xC: /*32k at B8000*/ mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); - mem_mapping_disable(&gd54xx->mmio_mapping); svga->banked_mask = 0x7fff; gd54xx->mmio_vram_overlap = 1; break; @@ -552,7 +580,7 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) uint32_t base, size; if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { - if (svga->gdcreg[0xb] & 0x20) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { base = (svga->seqregs[7] & 0xf0) << 16; size = 1 * 1024 * 1024; } else { @@ -577,7 +605,7 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); svga->linear_base = base; if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { - if (svga->seqregs[0x17] & 0x40) { + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) { if (size >= (4 * 1024 * 1024)) mem_mapping_disable(&gd54xx->mmio_mapping); /* MMIO is handled in the linear read/write functions */ else { @@ -602,45 +630,85 @@ gd54xx_recalctimings(svga_t *svga) svga->interlace = (svga->crtc[0x1a] & 0x01); - if (svga->seqregs[7] & 0x01) { - svga->render = svga_render_8bpp_highres; - svga->bpp = 8; - } else if (svga->gdcreg[5] & 0x40) { - svga->render = svga_render_8bpp_lowres; - svga->bpp = 8; - } - svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); - if (gd54xx->ramdac.ctrl & 0x80) { - if (gd54xx->ramdac.ctrl & 0x40) { - switch (gd54xx->ramdac.ctrl & 0xf) { - case 0x0: - svga->render = svga_render_15bpp_highres; - svga->bpp = 15; - break; - case 0x1: - svga->render = svga_render_16bpp_highres; - svga->bpp = 16; - break; - case 0x5: - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) && (svga->seqregs[7] & 8)) { - svga->render = svga_render_32bpp_highres; - svga->bpp = 32; - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) - svga->rowoffset *= 2; - } else { - svga->render = svga_render_24bpp_highres; - svga->bpp = 24; - } - break; - } - } else { - svga->render = svga_render_15bpp_highres; - svga->bpp = 15; + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) + { + svga->bpp = 8; + svga->render = svga_render_8bpp_highres; } + else if (svga->gdcreg[5] & 0x40) + { + svga->bpp = 8; + svga->render = svga_render_8bpp_lowres; } - + + if (gd54xx->ramdac.ctrl & 0x80) + { + if (gd54xx->ramdac.ctrl & 0x40) + { + switch (gd54xx->ramdac.ctrl & 0xf) + { + case 0: + svga->bpp = 15; + svga->render = svga_render_15bpp_highres; + break; + + case 1: + svga->bpp = 16; + svga->render = svga_render_16bpp_highres; + break; + + case 5: + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) && (svga->seqregs[7] & CIRRUS_SR7_BPP_32)) + { + svga->bpp = 32; + svga->render = svga_render_32bpp_highres; + if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + svga->rowoffset *= 2; + } + else + { + svga->bpp = 24; + svga->render = svga_render_24bpp_highres; + } + break; + + case 0xf: + switch (svga->seqregs[7] & CIRRUS_SR7_BPP_MASK) + { + case CIRRUS_SR7_BPP_32: + svga->bpp = 32; + svga->render = svga_render_32bpp_highres; + svga->rowoffset *= 2; + break; + + case CIRRUS_SR7_BPP_24: + svga->bpp = 24; + svga->render = svga_render_24bpp_highres; + break; + + case CIRRUS_SR7_BPP_16: + case CIRRUS_SR7_BPP_16_DOUBLEVCLK: + svga->bpp = 16; + svga->render = svga_render_16bpp_highres; + break; + + case CIRRUS_SR7_BPP_8: + svga->bpp = 8; + svga->render = svga_render_8bpp_highres; + break; + } + break; + } + } + else + { + svga->bpp = 15; + svga->render = svga_render_15bpp_highres; + } + } + clocksel = (svga->miscout >> 2) & 3; if (!gd54xx->vclk_n[clocksel] || !gd54xx->vclk_d[clocksel]) @@ -656,7 +724,7 @@ gd54xx_recalctimings(svga_t *svga) freq /= 2.0; break; case 4: - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5434) freq /= 3.0; break; } @@ -666,47 +734,50 @@ gd54xx_recalctimings(svga_t *svga) svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; } - -static void -gd54xx_hwcursor_draw(svga_t *svga, int displine) +static +void gd54xx_hwcursor_draw(svga_t *svga, int displine) { - int x; - uint8_t dat[2]; - int xx; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int largecur = (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE); - int cursize = (largecur) ? 64 : 32; - int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; - int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; - - if (svga->interlace && svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 4; - - for (x = 0; x < cursize; x += 8) { + int x; + uint8_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + for (x = 0; x < svga->hwcursor.xsize; x += 8) { dat[0] = svga->vram[svga->hwcursor_latch.addr]; - dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + if (svga->hwcursor.xsize == 64) + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + else + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; for (xx = 0; xx < 8; xx++) { if (offset >= svga->hwcursor_latch.x) { if (dat[1] & 0x80) - ((uint32_t *)buffer32->line[displine + y_add])[offset + cursize + x_add] = 0; + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = 0; if (dat[0] & 0x80) - ((uint32_t *)buffer32->line[displine + y_add])[offset + cursize + x_add] ^= 0xffffff; + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; } - + offset++; dat[0] <<= 1; dat[1] <<= 1; } svga->hwcursor_latch.addr++; - } - - if (svga->interlace && !svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 4; + } + + if (svga->hwcursor.xsize == 64) + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; } - static void -gd5428_copy_pixel(gd54xx_t *gd54xx, svga_t *svga, uint8_t src, uint8_t dst) +gd54xx_memsrc_rop(gd54xx_t *gd54xx, svga_t *svga, uint8_t src, uint8_t dst) { uint8_t res = src; svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; @@ -751,7 +822,7 @@ gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) for (x=0;x<32;x+=8) { pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) - gd5428_copy_pixel(gd54xx, svga, pixel, svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); + gd54xx_memsrc_rop(gd54xx, svga, pixel, svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); gd54xx->blt.dst_addr_backup++; gd54xx->blt.pixel_cnt++; } @@ -1123,7 +1194,7 @@ gd54xx_readb_linear(uint32_t addr, void *p) } if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) return gd543x_mmio_read(addr & 0x000000ff, gd54xx); } @@ -1143,7 +1214,7 @@ gd54xx_readw_linear(uint32_t addr, void *p) addr &= 0x003fffff; /* 4 MB mask */ if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { if (ap == 2) addr ^= 0x00000002; @@ -1199,7 +1270,7 @@ gd54xx_readl_linear(uint32_t addr, void *p) addr &= 0x003fffff; /* 4 MB mask */ if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); switch(ap) { @@ -1286,7 +1357,7 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) } if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); } @@ -1320,7 +1391,7 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) uint16_t temp; if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { switch(ap) { case 0: default: @@ -1394,7 +1465,7 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) uint32_t temp; if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { switch(ap) { case 0: default: @@ -1520,7 +1591,7 @@ gd54xx_readl(uint32_t addr, void *p) static int gd543x_do_mmio(svga_t *svga, uint32_t addr) { - if (svga->seqregs[0x17] & 0x40) + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) return 1; else return ((addr & ~0xff) == 0xb8000); @@ -1620,7 +1691,7 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) else gd54xx->blt.dst_addr &= 0x1fffff; - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.bltstart & 0x80)) { + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_AUTOSTART)) { if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { gd54xx->blt.sys_tx = 1; gd54xx->blt.sys_cnt = 0; @@ -1659,7 +1730,7 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) break; case 0x1b: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) gd54xx->blt.modeext = val; break; @@ -1680,8 +1751,8 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) break; case 0x40: - gd54xx->blt.bltstart = val; - if (gd54xx->blt.bltstart & 0x02) { + gd54xx->blt.status = val; + if (gd54xx->blt.status & CIRRUS_BLT_START) { if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { gd54xx->blt.sys_tx = 1; gd54xx->blt.sys_cnt = 0; @@ -1799,7 +1870,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) blt_mask *= 2; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) { x_max = 24; if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) @@ -1853,7 +1924,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); + mem_mapping_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); mem_mapping_set_p(&gd54xx->linear_mapping, svga); } gd543x_recalc_mapping(gd54xx); @@ -1892,7 +1963,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) } break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) { if ((gd54xx->blt.x_count % 3) == 2) src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); @@ -1941,8 +2012,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - pclog("Pattern copy\n"); - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 24)]; break; case CIRRUS_BLTMODE_PIXELWIDTH32: @@ -1966,7 +2036,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) { mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); if ((gd54xx->blt.dst_addr % 3) == 2) @@ -2039,7 +2109,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) { mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); if ((gd54xx->blt.dst_addr % 3) == 2) @@ -2074,7 +2144,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) switch (gd54xx->blt.rop) { case 0x00: dst = 0; break; case 0x05: dst = src & dst; break; - case 0x06: /* dst = dst; */ break; + case 0x06: dst = dst; break; case 0x09: dst = src & ~dst; break; case 0x0b: dst = ~ dst; break; case 0x0d: dst = src; break; @@ -2146,7 +2216,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); + mem_mapping_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); mem_mapping_set_p(&gd54xx->linear_mapping, svga); } gd543x_recalc_mapping(gd54xx); @@ -2172,16 +2242,9 @@ cl_pci_read(int func, int addr, void *p) case 0x01: return 0x10; case 0x02: - switch (svga->crtc[0x27]) { - case CIRRUS_ID_CLGD5430: - return 0xa0; - case CIRRUS_ID_CLGD5434: - return 0xa8; - case CIRRUS_ID_CLGD5436: - return 0xac; - } - return 0xff; + return svga->crtc[0x27]; case 0x03: return 0x00; + case PCI_REG_COMMAND: return gd54xx->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ @@ -2198,10 +2261,10 @@ cl_pci_read(int func, int addr, void *p) case 0x12: return 0x00; case 0x13: return gd54xx->lfb_base >> 24; - case 0x30: return (gd54xx->has_bios) ? (gd54xx->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ + case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ case 0x31: return 0x00; - case 0x32: return (gd54xx->has_bios) ? gd54xx->pci_regs[0x32] : 0x00; - case 0x33: return (gd54xx->has_bios) ? gd54xx->pci_regs[0x33] : 0x00; + case 0x32: return gd54xx->pci_regs[0x32]; + case 0x33: return gd54xx->pci_regs[0x33]; case 0x3c: return gd54xx->int_line; case 0x3d: return PCI_INTA; @@ -2230,8 +2293,6 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x30: case 0x32: case 0x33: - if (!(gd54xx->has_bios)) - return; gd54xx->pci_regs[addr] = val; if (gd54xx->pci_regs[0x30] & 0x01) { uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); @@ -2252,21 +2313,20 @@ static void { gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); svga_t *svga = &gd54xx->svga; - int id = info->local & 0x7FFF; + int id = info->local; wchar_t *romfn = NULL; memset(gd54xx, 0, sizeof(gd54xx_t)); - gd54xx->has_bios = !(info->local & 0x8000); - gd54xx->pci = !!(info->flags & DEVICE_PCI); gd54xx->vlb = !!(info->flags & DEVICE_VLB); switch (id) { + case CIRRUS_ID_CLGD5426: + romfn = BIOS_GD5426_PATH; + break; + case CIRRUS_ID_CLGD5428: - if (gd54xx->vlb) - romfn = BIOS_GD5428_VLB_PATH; - else - romfn = BIOS_GD5428_ISA_PATH; + romfn = BIOS_GD5428_PATH; break; case CIRRUS_ID_CLGD5429: @@ -2292,7 +2352,6 @@ static void gd54xx->vram_size = device_get_config_int("memory"); gd54xx->vram_mask = (gd54xx->vram_size << 20) - 1; - if (gd54xx->has_bios) rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, @@ -2307,23 +2366,6 @@ static void io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); - svga->decode_mask = (4 << 20) - 1; - - switch (gd54xx->vram_size) { - case 1: /*1MB*/ - svga->vram_mask = (1 << 20) - 1; - svga->vram_max = 1 << 20; - break; - case 2: /*2MB*/ - svga->vram_mask = (2 << 20) - 1; - svga->vram_max = 2 << 20; - break; - case 4: /*4MB*/ - svga->vram_mask = (4 << 20) - 1; - svga->vram_max = 4 << 20; - break; - } - svga->hwcursor.yoff = 32; svga->hwcursor.xoff = 0; @@ -2334,10 +2376,10 @@ static void gd54xx->bank[1] = 0x8000; - if ((info->flags & DEVICE_PCI) && id >= CIRRUS_ID_CLGD5430) + if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); - gd54xx->pci_regs[0x04] = 7; + gd54xx->pci_regs[PCI_REG_COMMAND] = 7; gd54xx->pci_regs[0x30] = 0x00; gd54xx->pci_regs[0x32] = 0x0c; @@ -2349,19 +2391,17 @@ static void } static int -gd5428_isa_available(void) +gd5426_available(void) { - return rom_present(BIOS_GD5428_ISA_PATH); + return rom_present(BIOS_GD5426_PATH); } - static int -gd5428_vlb_available(void) +gd5428_available(void) { - return rom_present(BIOS_GD5428_VLB_PATH); + return rom_present(BIOS_GD5428_PATH); } - static int gd5429_available(void) { @@ -2396,7 +2436,7 @@ void gd54xx_close(void *p) { gd54xx_t *gd54xx = (gd54xx_t *)p; - + svga_close(&gd54xx->svga); free(gd54xx); @@ -2484,6 +2524,20 @@ static device_config_t gd5434_config[] = } }; +device_t gd5426_vlb_device = +{ + "Cirrus Logic CL-GD 5426 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5426, + gd54xx_init, + gd54xx_close, + NULL, + gd5426_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd54xx_add_status_info, + gd5428_config +}; device_t gd5428_isa_device = { @@ -2493,7 +2547,7 @@ device_t gd5428_isa_device = gd54xx_init, gd54xx_close, NULL, - gd5428_isa_available, + gd5428_available, gd54xx_speed_changed, gd54xx_force_redraw, gd54xx_add_status_info, @@ -2508,7 +2562,7 @@ device_t gd5428_vlb_device = gd54xx_init, gd54xx_close, NULL, - gd5428_vlb_available, + gd5428_available, gd54xx_speed_changed, gd54xx_force_redraw, gd54xx_add_status_info, diff --git a/src/video/vid_cl54xx.h b/src/video/vid_cl54xx.h index 2bf9e6aaf..472d8316b 100644 --- a/src/video/vid_cl54xx.h +++ b/src/video/vid_cl54xx.h @@ -1,6 +1,7 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ +extern device_t gd5426_vlb_device; extern device_t gd5428_isa_device; extern device_t gd5428_vlb_device; extern device_t gd5429_isa_device; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index 56800e09d..b4b239697 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -158,6 +158,7 @@ video_cards[] = { #if defined(DEV_BRANCH) && defined(USE_STEALTH32) {"[VLB] Diamond Stealth 32 (Tseng ET4000/w32p)","stealth32_vlb", &et4000w32p_vlb_device, GFX_ET4000W32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, #endif + {"[VLB] Diamond SpeedStar PRO (CL-GD5426)", "cl_gd5426_vlb", &gd5426_vlb_device, GFX_CL_GD5426_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, {"[VLB] Diamond SpeedStar PRO SE (CL-GD5430)", "cl_gd5430_vlb", &gd5430_vlb_device, GFX_CL_GD5430_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, {"[VLB] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_vlb",&s3_virge_vlb_device, GFX_VIRGE_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, {"[VLB] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_vlb",&s3_virge_988_vlb_device, GFX_VIRGEVX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}}, diff --git a/src/video/video.h b/src/video/video.h index 7b2fadd1a..33d92106c 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -76,11 +76,12 @@ enum { GFX_MACH64VT2, /* ATI Mach64 VT2 */ GFX_CL_GD5424_ISA, /* Cirrus Logic CL-GD 5424 ISA */ GFX_CL_GD5424_VLB, /* Cirrus Logic CL-GD 5424 VLB */ + GFX_CL_GD5426_VLB, /* Diamond SpeedStar PRO (Cirrus Logic CL-GD 5426) VLB */ GFX_CL_GD5428_ISA, /* Cirrus Logic CL-GD 5428 ISA */ - GFX_CL_GD5428_VLB, /* Diamond SpeedStar PRO (Cirrus Logic CL-GD 5428) VLB */ + GFX_CL_GD5428_VLB, /* Cirrus Logic CL-GD 5428 VLB */ GFX_CL_GD5429_ISA, /* Cirrus Logic CL-GD 5429 ISA */ GFX_CL_GD5429_VLB, /* Cirrus Logic CL-GD 5429 VLB */ - GFX_CL_GD5430_VLB, /* Diamond SpeedStar PRO SE (Cirrus Logic CL-GD 5430) PCI */ + GFX_CL_GD5430_VLB, /* Diamond SpeedStar PRO SE (Cirrus Logic CL-GD 5430) VLB */ GFX_CL_GD5430_PCI, /* Cirrus Logic CL-GD 5430 PCI */ GFX_CL_GD5434_ISA, /* Cirrus Logic CL-GD 5434 ISA */ GFX_CL_GD5434_VLB, /* Cirrus Logic CL-GD 5434 VLB */ From 3b62e83315578892708072c5ebd952d787047946 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 15 Mar 2018 22:57:24 +0100 Subject: [PATCH 14/23] Ported some IDE and ATAPI-related improvements from PCem; Fixed the ATI 18800 emulation; More tweaks to reduce RAM usage. --- src/cdrom/cdrom.c | 93 ++++++++++++-------------------- src/cdrom/cdrom.h | 6 +-- src/cdrom/cdrom_image.cc | 10 ++-- src/disk/hdc_ide.c | 103 +++++++++++++++++++++++++++--------- src/disk/zip.c | 91 +++++++++++-------------------- src/machine/machine.c | 5 +- src/mem.c | 69 ++++++++++++++++-------- src/mem.h | 3 ++ src/pc.c | 3 +- src/video/vid_ati18800.c | 27 +++++++++- src/video/vid_ati28800.c | 4 +- src/video/vid_svga_render.c | 6 +-- src/video/vid_table.c | 13 +++-- src/video/video.c | 14 +++-- src/video/video.h | 8 ++- src/win/win_cdrom_ioctl.c | 12 ++--- 16 files changed, 269 insertions(+), 198 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 5a50c0cd7..502821ab6 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.c 1.0.34 2018/03/06 + * Version: @(#)cdrom.c 1.0.35 2018/03/15 * * Author: Miran Grca, * @@ -886,12 +886,6 @@ static void cdrom_unit_attention(uint8_t id) cdrom_log("CD-ROM %i: UNIT ATTENTION\n", id); } -static void cdrom_bus_master_error(uint8_t id) -{ - cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; - cdrom_cmd_error(id); -} - static void cdrom_not_ready(uint8_t id) { cdrom_sense_key = SENSE_NOT_READY; @@ -2722,17 +2716,12 @@ int cdrom_read_from_ide_dma(uint8_t channel) return 0; if (ide_bus_master_write) { - if (ide_bus_master_write(channel >> 1, cdbufferb, cdrom[id].packet_len)) { - cdrom_bus_master_error(id); - cdrom_phase_callback(id); + if (ide_bus_master_write(channel >> 1, cdbufferb, cdrom[id].packet_len)) return 0; - } else + else return 1; - } else { - cdrom_bus_master_error(id); - cdrom_phase_callback(id); + } else return 0; - } return 0; } @@ -2750,6 +2739,12 @@ int cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) return 1; } +void cdrom_irq_raise(uint8_t id) +{ + if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) + ide_irq_raise(&(ide_drives[cdrom_drives[id].ide_channel])); +} + int cdrom_read_from_dma(uint8_t id) { int32_t *BufLen = &SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].BufferLength; @@ -2770,43 +2765,33 @@ int cdrom_read_from_dma(uint8_t id) cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", id, cdrom[id].packet_len); ret = cdrom_phase_data_out(id); - if (!ret) { - cdrom_phase_callback(id); - return 0; - } else - return 1; - return 0; + if (ret) { + cdrom_buf_free(id); + cdrom[id].packet_status = CDROM_PHASE_COMPLETE; + cdrom[id].status = READY_STAT; + cdrom[id].phase = 3; + ui_sb_update_icon(SB_CDROM | id, 0); + cdrom_irq_raise(id); + return 1; + } else + return 0; } int cdrom_write_to_ide_dma(uint8_t channel) { uint8_t id = atapi_cdrom_drives[channel]; - if (id > CDROM_NUM) { - cdrom_log("CD-ROM %i: Drive not found\n", id); + if (id > CDROM_NUM) return 0; - } if (ide_bus_master_read) { - if (ide_bus_master_read(channel >> 1, cdbufferb, cdrom[id].packet_len)) { - cdrom_log("CD-ROM %i: ATAPI DMA error\n", id); - cdrom_bus_master_error(id); - cdrom_phase_callback(id); + if (ide_bus_master_read(channel >> 1, cdbufferb, cdrom[id].packet_len)) return 0; - } - else { - cdrom_log("CD-ROM %i: ATAPI DMA success\n", id); + else return 1; - } - } else { - cdrom_log("CD-ROM %i: No bus master\n", id); - cdrom_bus_master_error(id); - cdrom_phase_callback(id); + } else return 0; - } - - return 0; } int cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) @@ -2834,16 +2819,16 @@ int cdrom_write_to_dma(uint8_t id) } else ret = cdrom_write_to_ide_dma(cdrom_drives[id].ide_channel); - if (!ret) + if (ret) { + cdrom_buf_free(id); + cdrom[id].packet_status = CDROM_PHASE_COMPLETE; + cdrom[id].status = READY_STAT; + cdrom[id].phase = 3; + ui_sb_update_icon(SB_CDROM | id, 0); + cdrom_irq_raise(id); + return 1; + } else return 0; - - return 1; -} - -void cdrom_irq_raise(uint8_t id) -{ - if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) - ide_irq_raise(&(ide_drives[cdrom_drives[id].ide_channel])); } /* If the result is 1, issue an IRQ, otherwise not. */ @@ -2879,12 +2864,6 @@ void cdrom_phase_callback(uint8_t id) case CDROM_PHASE_DATA_OUT_DMA: cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA\n", id); cdrom_read_from_dma(id); - cdrom_buf_free(id); - cdrom[id].packet_status = CDROM_PHASE_COMPLETE; - cdrom[id].status = READY_STAT; - cdrom[id].phase = 3; - ui_sb_update_icon(SB_CDROM | id, 0); - cdrom_irq_raise(id); return; case CDROM_PHASE_DATA_IN: cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN\n", id); @@ -2895,12 +2874,6 @@ void cdrom_phase_callback(uint8_t id) case CDROM_PHASE_DATA_IN_DMA: cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", id); cdrom_write_to_dma(id); - cdrom_buf_free(id); - cdrom[id].packet_status = CDROM_PHASE_COMPLETE; - cdrom[id].status = READY_STAT; - cdrom[id].phase = 3; - ui_sb_update_icon(SB_CDROM | id, 0); - cdrom_irq_raise(id); return; case CDROM_PHASE_ERROR: cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", id); diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index d82a002cb..d463e8a25 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.h 1.0.5 2018/03/06 + * Version: @(#)cdrom.h 1.0.6 2018/03/15 * * Author: Miran Grca, * @@ -148,6 +148,8 @@ typedef struct { int block_descriptor_len; int init_length; + + int16_t cd_buffer[BUF_SIZE]; } cdrom_t; typedef struct { @@ -187,7 +189,6 @@ typedef struct { int cd_state; uint32_t cd_pos; uint32_t cd_end; - int16_t cd_buffer[BUF_SIZE]; int cd_buflen; } cdrom_image_t; @@ -199,7 +200,6 @@ typedef struct { int tocvalid; int cd_state; uint32_t cd_end; - int16_t cd_buffer[BUF_SIZE]; int cd_buflen; int actual_requested_blocks; int last_track_pos; diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.cc index da066c360..f8e32c75c 100644 --- a/src/cdrom/cdrom_image.cc +++ b/src/cdrom/cdrom_image.cc @@ -80,9 +80,9 @@ void image_audio_callback(uint8_t id, int16_t *output, int len) { if (cdrom[id].seek_pos < cdrom_image[id].cd_end) { - if (!cdimg[id]->ReadSector((unsigned char*)&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], true, cdrom[id].seek_pos)) + if (!cdimg[id]->ReadSector((unsigned char*)&cdrom[id].cd_buffer[cdrom_image[id].cd_buflen], true, cdrom[id].seek_pos)) { - memset(&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); + memset(&cdrom[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); cdrom_image[id].cd_state = CD_STOPPED; cdrom_image[id].cd_buflen = len; } @@ -94,13 +94,13 @@ void image_audio_callback(uint8_t id, int16_t *output, int len) } else { - memset(&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); + memset(&cdrom[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); cdrom_image[id].cd_state = CD_STOPPED; cdrom_image[id].cd_buflen = len; } } - memcpy(output, cdrom_image[id].cd_buffer, len * 2); - memmove(cdrom_image[id].cd_buffer, &cdrom_image[id].cd_buffer[len], (BUF_SIZE - len) * 2); + memcpy(output, cdrom[id].cd_buffer, len * 2); + memmove(cdrom[id].cd_buffer, &cdrom[id].cd_buffer[len], (BUF_SIZE - len) * 2); cdrom_image[id].cd_buflen -= len; } diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 91696880b..3d572d035 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.32 2018/03/06 + * Version: @(#)hdc_ide.c 1.0.33 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -90,6 +90,14 @@ #define WIN_SET_FEATURES 0xEF #define WIN_READ_NATIVE_MAX 0xF8 +#define FEATURE_SET_TRANSFER_MODE 0x03 +#define FEATURE_ENABLE_IRQ_OVERLAPPED 0x5d +#define FEATURE_ENABLE_IRQ_SERVICE 0x5e +#define FEATURE_DISABLE_REVERT 0x66 +#define FEATURE_ENABLE_REVERT 0xcc +#define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd +#define FEATURE_DISABLE_IRQ_SERVICE 0xde + enum { IDE_NONE = 0, @@ -397,11 +405,13 @@ static void ide_identify(IDE *ide) if (ide->buffer[49] & (1 << 8)) { - ide->buffer[52] = 2 << 8; /*DMA timing mode*/ + ide->buffer[51] = 120; + ide->buffer[52] = 120; /*DMA timing mode*/ ide->buffer[53] |= 6; ide->buffer[62] = 7; ide->buffer[63] = 7; + ide->buffer[64] = 3; /*PIO Modes 3 & 4*/ ide->buffer[88] = 7; if (ide->mdma_mode != -1) { @@ -411,7 +421,10 @@ static void ide_identify(IDE *ide) ide->buffer[88] |= d; else if ((ide->mdma_mode & 0x300) == 0x100) ide->buffer[63] |= d; - else + else if ((ide->mdma_mode & 0x300) == 0x400) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else ide->buffer[62] |= d; ide_log(" IDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); } @@ -452,10 +465,12 @@ static void ide_atapi_identify(IDE *ide) if (PCI && (ide->board < 2) && (cdrom_drives[cdrom_id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) { ide->buffer[49] |= 0x100; /* DMA supported */ - ide->buffer[52] = 2 << 8; /*DMA timing mode*/ + ide->buffer[51] = 120; + ide->buffer[52] = 120; /*DMA timing mode*/ ide->buffer[53] = 7; ide->buffer[62] = 7; ide->buffer[63] = 7; + ide->buffer[64] = 3; /*PIO Modes 3 & 4*/ ide->buffer[88] = 7; if (ide->mdma_mode != -1) { @@ -465,12 +480,16 @@ static void ide_atapi_identify(IDE *ide) ide->buffer[88] |= d; else if ((ide->mdma_mode & 0x300) == 0x100) ide->buffer[63] |= d; - else + else if ((ide->mdma_mode & 0x300) == 0x400) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else ide->buffer[62] |= d; ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); } - ide->buffer[65] = 0xb4; - ide->buffer[66] = 0xb4; + ide->buffer[65] = 120; + ide->buffer[66] = 120; + ide->buffer[67] = 120; ide->buffer[71] = 30; ide->buffer[72] = 30; ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ @@ -506,26 +525,42 @@ static void ide_atapi_zip_identify(IDE *ide) if (PCI && (ide->board < 2) && (zip_drives[zip_id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) { ide->buffer[49] |= 0x100; /* DMA supported */ - ide->buffer[52] = 0 << 8; /*DMA timing mode*/ - ide->buffer[53] = 6; - ide->buffer[63] = 3; - ide->buffer[88] = 7; - if (ide->mdma_mode != -1) + if (zip_drives[zip_id].is_250) { + ide->buffer[52] = 0 << 8; /*DMA timing mode*/ + ide->buffer[53] = 6; + ide->buffer[63] = 3; + ide->buffer[88] = 7; + ide->buffer[64] = 0x0001; /*PIO Mode 3*/ + ide->buffer[65] = 0x96; + ide->buffer[66] = 0x96; + ide->buffer[67] = 0xb4; + ide->buffer[68] = 0xb4; + ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ + ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ + } else { + ide->buffer[51] = 120; + ide->buffer[52] = 120; + ide->buffer[53] = 2; /*Words 64-70 are valid*/ + ide->buffer[63] = 0x0003; /*Multi-word DMA 0 & 1*/ + ide->buffer[64] = 0x0001; /*PIO Mode 3*/ + ide->buffer[65] = 120; + ide->buffer[66] = 120; + ide->buffer[67] = 120; + } + + if (ide->mdma_mode != -1) { d = (ide->mdma_mode & 0xff); d <<= 8; if ((ide->mdma_mode & 0x300) == 0x200) ide->buffer[88] |= d; - else + else if ((ide->mdma_mode & 0x300) == 0x400) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else ide->buffer[63] |= d; ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); } - ide->buffer[65] = 0x96; - ide->buffer[66] = 0x96; - ide->buffer[67] = 0xb4; - ide->buffer[68] = 0xb4; - ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ - ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ } } @@ -631,14 +666,25 @@ static int ide_set_features(IDE *ide) if (ide_drive_is_zip(ide)) { bus = zip_drives[atapi_zip_drives[ide->channel]].bus_type; dma = (bus == ZIP_BUS_ATAPI_PIO_AND_DMA); - max_pio = 0; + if (!PCI || !dma || (ide->board >= 2)) + max_pio = 0; + else + max_pio = 3; max_mdma = 1; } else if (ide_drive_is_cdrom(ide)) { bus = cdrom_drives[atapi_cdrom_drives[ide->channel]].bus_type; dma = (bus == CDROM_BUS_ATAPI_PIO_AND_DMA); + if (!PCI || !dma || (ide->board >= 2)) + max_pio = 0; + else + max_pio = 4; } else { bus = hdd[ide->hdd_num].bus; dma = (bus == HDD_BUS_IDE_PIO_AND_DMA); + if (!PCI || !dma || (ide->board >= 2)) + max_pio = 0; + else + max_pio = 2; } ide_log("Features code %02X\n", features); @@ -647,7 +693,7 @@ static int ide_set_features(IDE *ide) switch(features) { - case 0x03: /* Set transfer mode. */ + case FEATURE_SET_TRANSFER_MODE: /* Set transfer mode. */ ide_log("Transfer mode %02X\n", features_data >> 3); mode = (features_data >> 3); @@ -669,7 +715,7 @@ static int ide_set_features(IDE *ide) { return 0; } - ide->mdma_mode = -1; + ide->mdma_mode = (1 << submode) | 0x400; ide_log("IDE %02X: Setting PIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); break; @@ -704,8 +750,17 @@ static int ide_set_features(IDE *ide) return 0; } - case 0x66: /* Disable reverting to power on defaults. */ - case 0xCC: /* Enable reverting to power on defaults. */ + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + if (!PCI || !dma || (ide->board >= 2)) + return 0; + else + return 1; + + case FEATURE_DISABLE_REVERT: /* Disable reverting to power on defaults. */ + case FEATURE_ENABLE_REVERT: /* Enable reverting to power on defaults. */ return 1; default: diff --git a/src/disk/zip.c b/src/disk/zip.c index cd20e2253..e6b2689de 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -9,7 +9,7 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.c 1.0.8 2018/03/07 + * Version: @(#)zip.c 1.0.9 2018/03/15 * * Author: Miran Grca, * @@ -1084,12 +1084,6 @@ static void zip_unit_attention(uint8_t id) zip_log("ZIP %i: UNIT ATTENTION\n", id); } -static void zip_bus_master_error(uint8_t id) -{ - zip_sense_key = zip_asc = zip_ascq = 0; - zip_cmd_error(id); -} - static void zip_not_ready(uint8_t id) { zip_sense_key = SENSE_NOT_READY; @@ -2220,19 +2214,12 @@ int zip_read_from_ide_dma(uint8_t channel) return 0; if (ide_bus_master_write) { - if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) { - zip_bus_master_error(id); - zip_phase_callback(id); + if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) return 0; - } else + else return 1; - } else { - zip_bus_master_error(id); - zip_phase_callback(id); + } else return 0; - } - - return 0; } int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) @@ -2248,6 +2235,12 @@ int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) return 1; } +void zip_irq_raise(uint8_t id) +{ + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + ide_irq_raise(&(ide_drives[zip_drives[id].ide_channel])); +} + int zip_read_from_dma(uint8_t id) { int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; @@ -2273,13 +2266,17 @@ int zip_read_from_dma(uint8_t id) } ret = zip_phase_data_out(id); - if (!ret) { - zip_phase_callback(id); - return 0; - } else - return 1; - return 0; + if (ret) { + zip_buf_free(id); + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].status = READY_STAT; + zip[id].phase = 3; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + return 1; + } else + return 0; } int zip_write_to_ide_dma(uint8_t channel) @@ -2292,24 +2289,12 @@ int zip_write_to_ide_dma(uint8_t channel) } if (ide_bus_master_read) { - if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) { - zip_log("ZIP %i: ATAPI DMA error\n", id); - zip_bus_master_error(id); - zip_phase_callback(id); + if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) return 0; - } - else { - zip_log("ZIP %i: ATAPI DMA success\n", id); + else return 1; - } - } else { - zip_log("ZIP %i: No bus master\n", id); - zip_bus_master_error(id); - zip_phase_callback(id); + } else return 0; - } - - return 0; } int zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) @@ -2337,16 +2322,16 @@ int zip_write_to_dma(uint8_t id) } else ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); - if (!ret) + if (ret) { + zip_buf_free(id); + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].status = READY_STAT; + zip[id].phase = 3; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + return 1; + } else return 0; - - return 1; -} - -void zip_irq_raise(uint8_t id) -{ - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - ide_irq_raise(&(ide_drives[zip_drives[id].ide_channel])); } /* If the result is 1, issue an IRQ, otherwise not. */ @@ -2382,12 +2367,6 @@ void zip_phase_callback(uint8_t id) case ZIP_PHASE_DATA_OUT_DMA: zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); zip_read_from_dma(id); - zip_buf_free(id); - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].status = READY_STAT; - zip[id].phase = 3; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); return; case ZIP_PHASE_DATA_IN: zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); @@ -2398,12 +2377,6 @@ void zip_phase_callback(uint8_t id) case ZIP_PHASE_DATA_IN_DMA: zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); zip_write_to_dma(id); - zip_buf_free(id); - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].status = READY_STAT; - zip[id].phase = 3; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); return; case ZIP_PHASE_ERROR: zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); diff --git a/src/machine/machine.c b/src/machine/machine.c index d43707b4f..a000a9fb5 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.c 1.0.29 2018/01/16 + * Version: @(#)machine.c 1.0.30 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -52,6 +52,9 @@ machine_init(void) AT = IS_ARCH(machine, MACHINE_AT); PCI = IS_ARCH(machine, MACHINE_PCI); + /* Resize the memory. */ + mem_resize(); + /* Load the machine's ROM BIOS. */ rom_load_bios(romset); mem_add_bios(); diff --git a/src/mem.c b/src/mem.c index 93ae0ec47..7bb2a12bc 100644 --- a/src/mem.c +++ b/src/mem.c @@ -1317,6 +1317,42 @@ void mem_a20_init(void) } } +void mem_destroy_pages(void) +{ + if (pages) { + free(pages); + pages = NULL; + } +} + +void mem_resize_pages(void) +{ + int total_size, c; + + mem_destroy_pages(); + + if (AT) { + if (cpu_16bitbus) + total_size = 4096; + else + total_size = 1048576; + } else + total_size = 256; + + pclog("%i pages\n", total_size); + + pages = malloc(total_size * sizeof(page_t)); + + memset(pages, 0, total_size * sizeof(page_t)); + + for (c = 0; c < total_size; c++) + { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } +} void mem_init(void) { @@ -1338,22 +1374,13 @@ void mem_init(void) writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); rom = NULL; biosmask = 0xffff; - pages = malloc((1 << 20) * sizeof(page_t)); - page_lookup = malloc((1 << 20) * sizeof(page_t *)); - - memset(pages, 0, (1 << 20) * sizeof(page_t)); - - memset(page_lookup, 0, (1 << 20) * sizeof(page_t *)); memset(ram_mapped_addr, 0, 64 * sizeof(uint32_t)); - - for (c = 0; c < (1 << 20); c++) - { - pages[c].mem = &ram[c << 12]; - pages[c].write_b = mem_write_ramb_page; - pages[c].write_w = mem_write_ramw_page; - pages[c].write_l = mem_write_raml_page; - } + + page_lookup = malloc((1 << 20) * sizeof(page_t *)); + memset(page_lookup, 0, (1 << 20) * sizeof(page_t *)); + + mem_resize_pages(); memset(isram, 0, sizeof(isram)); for (c = 0; c < (mem_size / 64); c++) @@ -1524,15 +1551,6 @@ void mem_resize() memset(ram, 0, (mem_size + 384) * 1024); } - memset(pages, 0, (1 << 20) * sizeof(page_t)); - for (c = 0; c < (1 << 20); c++) - { - pages[c].mem = &ram[c << 12]; - pages[c].write_b = mem_write_ramb_page; - pages[c].write_w = mem_write_ramw_page; - pages[c].write_l = mem_write_raml_page; - } - memset(isram, 0, sizeof(isram)); for (c = 0; c < (mem_size / 64); c++) { @@ -1541,6 +1559,8 @@ void mem_resize() isram[c] = 0; } + mem_resize_pages(); + memset(_mem_read_b, 0, sizeof(_mem_read_b)); memset(_mem_read_w, 0, sizeof(_mem_read_w)); memset(_mem_read_l, 0, sizeof(_mem_read_l)); @@ -1587,6 +1607,9 @@ void mem_resize() void mem_reset_page_blocks() { int c; + + if (!pages) + return; for (c = 0; c < ((mem_size * 1024) >> 12); c++) { diff --git a/src/mem.h b/src/mem.h index 9a5583d36..e31b3b1b2 100644 --- a/src/mem.h +++ b/src/mem.h @@ -240,6 +240,9 @@ extern void mem_add_bios(void); extern void mem_init(void); extern void mem_resize(void); +extern void mem_destroy_pages(void); +extern void mem_resize_pages(void); + extern uint8_t port_92_read(uint16_t port, void *priv); extern void port_92_write(uint16_t port, uint8_t val, void *priv); extern void port_92_clear_reset(void); diff --git a/src/pc.c b/src/pc.c index 3ecc85ab2..8ec023651 100644 --- a/src/pc.c +++ b/src/pc.c @@ -779,7 +779,6 @@ pc_reset_hard_init(void) /* Reset the general machine support modules. */ io_init(); // cpu_set(); - mem_resize(); timer_reset(); device_init(); @@ -967,6 +966,8 @@ pc_close(thread_t *ptr) network_close(); sound_cd_thread_end(); + + mem_destroy_pages(); } diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index bb02c5cec..3c047dc7d 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -8,7 +8,7 @@ * * ATI 18800 emulation (VGA Edge-16) * - * Version: @(#)vid_ati18800.c 1.0.5 2018/02/07 + * Version: @(#)vid_ati18800.c 1.0.6 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -31,6 +31,7 @@ #include "vid_ati18800.h" #include "vid_ati_eeprom.h" #include "vid_svga.h" +#include "vid_svga_render.h" #define BIOS_ROM_PATH_WONDER L"roms/video/ati18800/VGA_Wonder_V3-1.02.bin" @@ -159,6 +160,28 @@ static uint8_t ati18800_in(uint16_t addr, void *p) return temp; } +static void ati18800_recalctimings(svga_t *svga) +{ + ati18800_t *ati18800 = (ati18800_t *)svga->p; + + if(svga->crtc[0x17] & 4) + { + svga->vtotal <<= 1; + svga->dispend <<= 1; + svga->vsyncstart <<= 1; + svga->split <<= 1; + svga->vblankstart <<= 1; + } + + if (!svga->scrblank && (ati18800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + { + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + svga->rowoffset <<= 1; + svga->ma <<= 1; + } +} + static void *ati18800_init(device_t *info) { ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); @@ -178,7 +201,7 @@ static void *ati18800_init(device_t *info) }; svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ - NULL, + ati18800_recalctimings, ati18800_in, ati18800_out, NULL, NULL); diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 5a9c7093f..7c6b64a51 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -8,7 +8,7 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * Version: @(#)vid_ati28800.c 1.0.10 2018/03/12 + * Version: @(#)vid_ati28800.c 1.0.11 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -273,7 +273,7 @@ uint8_t ati28800k_in(uint16_t addr, void *p) switch(get_korean_font_kind >> 8) { case 4: /* ROM font */ - temp = fontdatksc5601[get_korean_font_base][get_korean_font_index++]; + temp = fontdatksc5601[get_korean_font_base].chr[get_korean_font_index++]; break; case 2: /* User defined font - TODO : Should be implemented later */ temp = 0; diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index 818e25d57..fcef68564 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -8,7 +8,7 @@ * * SVGA renderers. * - * Version: @(#)vid_svga_render.c 1.0.8 2018/03/12 + * Version: @(#)vid_svga_render.c 1.0.9 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -311,7 +311,7 @@ void svga_render_text_80_ksc5601(svga_t *svga) if(x + xinc < svga->hdisp && (chr & nextchr & 0x80)) { - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc]; + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc]; } else { @@ -358,7 +358,7 @@ void svga_render_text_80_ksc5601(svga_t *svga) } } - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc + 16]; + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc + 16]; if (svga->seqregs[1] & 1) { for (xx = 0; xx < 8; xx++) diff --git a/src/video/vid_table.c b/src/video/vid_table.c index b4b239697..d52c6d963 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -8,7 +8,7 @@ * * Define all known video cards. * - * Version: @(#)vid_table.c 1.0.23 2018/03/11 + * Version: @(#)vid_table.c 1.0.24 2018/03/15 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -98,9 +98,9 @@ video_cards[] = { #endif { "[ISA] CGA", "cga", &cga_device, GFX_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, { "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device, GFX_SUPER_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, - { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device, GFX_CL_GD5428_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - { "[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device, GFX_CL_GD5429_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, - { "[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device, GFX_CL_GD5434_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, + { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device, GFX_CL_GD5428_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, + { "[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device, GFX_CL_GD5429_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, + { "[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device, GFX_CL_GD5434_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, { "[ISA] Compaq ATI VGA Wonder XL (ATI-28800-5)","compaq_ati28800", &compaq_ati28800_device, GFX_VGAWONDERXL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, { "[ISA] Compaq CGA", "compaq_cga", &compaq_cga_device, GFX_COMPAQ_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, { "[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device, GFX_COMPAQ_CGA_2, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, @@ -190,6 +190,11 @@ video_reset(int card) if ((card == GFX_NONE) || \ (card == GFX_INTERNAL) || machines[machine].fixed_gfxcard) return; + if (fontdatksc5601) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } + pclog("VIDEO: initializing '%s'\n", video_cards[video_old_to_new(card)].name); /* Initialize the video card. */ device_add(video_cards[video_old_to_new(card)].device); diff --git a/src/video/video.c b/src/video/video.c index 19a3a7efc..728b9799d 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -40,7 +40,7 @@ * W = 3 bus clocks * L = 4 bus clocks * - * Version: @(#)video.c 1.0.18 2018/03/02 + * Version: @(#)video.c 1.0.19 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -79,7 +79,7 @@ uint8_t fontdat[2048][8]; /* IBM CGA font */ uint8_t fontdatm[2048][16]; /* IBM MDA font */ uint8_t fontdatw[512][32]; /* Wyse700 font */ uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ -uint8_t fontdatksc5601[16384][32]; /* Korean KSC-5601 font */ +dbcs_font_t *fontdatksc5601;; /* Korean KSC-5601 font */ uint32_t pal_lookup[256]; int xsize = 1, ysize = 1; @@ -656,6 +656,11 @@ video_close(void) destroy_bitmap(buffer); destroy_bitmap(buffer32); + + if (fontdatksc5601) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } } @@ -765,11 +770,14 @@ loadfont(wchar_t *s, int format) break; case 6: /* Korean KSC-5601 */ + if (!fontdatksc5601) + fontdatksc5601 = malloc(16384 * sizeof(dbcs_font_t)); + for (c=0;c<16384;c++) { for (d=0;d<32;d++) { - fontdatksc5601[c][d]=getc(f); + fontdatksc5601[c].chr[d]=getc(f); } } break; diff --git a/src/video/video.h b/src/video/video.h index 33d92106c..1813e8115 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -8,7 +8,7 @@ * * Definitions for the video controller module. * - * Version: @(#)video.h 1.0.22 2018/03/02 + * Version: @(#)video.h 1.0.23 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -151,6 +151,10 @@ typedef struct { uint8_t r, g, b; } rgb_t; +typedef struct { + uint8_t chr[32]; +} dbcs_font_t; + typedef rgb_t PALETTE[256]; @@ -171,7 +175,7 @@ extern int video_fullscreen, extern int fullchange; extern uint8_t fontdat[2048][8]; extern uint8_t fontdatm[2048][16]; -extern uint8_t fontdatksc5601[16384][32]; +extern dbcs_font_t *fontdatksc5601; extern uint32_t *video_6to8, *video_15to32, *video_16to32; diff --git a/src/win/win_cdrom_ioctl.c b/src/win/win_cdrom_ioctl.c index b07527f2b..4dd160986 100644 --- a/src/win/win_cdrom_ioctl.c +++ b/src/win/win_cdrom_ioctl.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM host drive IOCTL interface for * Windows using SCSI Passthrough Direct. * - * Version: @(#)cdrom_ioctl.c 1.0.12 2018/02/25 + * Version: @(#)cdrom_ioctl.c 1.0.13 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -98,9 +98,9 @@ void ioctl_audio_callback(uint8_t id, int16_t *output, int len) in.DiskOffset.HighPart = 0; in.SectorCount = 1; in.TrackMode = CDDA; - if (!DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 2352, &count, NULL)) + if (!DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &(cdrom[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 2352, &count, NULL)) { - memset(&(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); + memset(&(cdrom[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); cdrom_ioctl_windows[id].is_playing = 0; ioctl_close(id); cdrom_ioctl[id].cd_state = CD_STOPPED; @@ -114,15 +114,15 @@ void ioctl_audio_callback(uint8_t id, int16_t *output, int len) } else { - memset(&(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); + memset(&(cdrom[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); cdrom_ioctl_windows[id].is_playing = 0; ioctl_close(id); cdrom_ioctl[id].cd_state = CD_STOPPED; cdrom_ioctl[id].cd_buflen = len; } } - memcpy(output, cdrom_ioctl[id].cd_buffer, len * 2); - memcpy(&cdrom_ioctl[id].cd_buffer[0], &(cdrom_ioctl[id].cd_buffer[len]), (BUF_SIZE - len) * 2); + memcpy(output, cdrom[id].cd_buffer, len * 2); + memcpy(&cdrom[id].cd_buffer[0], &(cdrom[id].cd_buffer[len]), (BUF_SIZE - len) * 2); cdrom_ioctl[id].cd_buflen -= len; } From 3759cbaad079128fafad9461b61fa8a65da377b9 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 15 Mar 2018 23:15:33 +0100 Subject: [PATCH 15/23] Ported the AudioPCI-related commits from PCem. --- src/sound/snd_audiopci.c | 251 ++++++++++++++++++++++++++++++++------- 1 file changed, 211 insertions(+), 40 deletions(-) diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index 979972102..716327192 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -3,6 +3,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include "../86box.h" #include "../device.h" @@ -15,6 +16,12 @@ #include "snd_audiopci.h" +#define N 16 + +#define ES1371_NCoef 91 + +static float low_fir_es1371_coef[ES1371_NCoef]; + typedef struct { uint8_t pci_command, pci_serr; @@ -55,6 +62,9 @@ typedef struct { int16_t buffer_l[64], buffer_r[64]; int buffer_pos, buffer_pos_end; + int filtered_l[32], filtered_r[32]; + int f_pos; + int16_t out_l, out_r; int32_t vol_l, vol_r; @@ -490,6 +500,7 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0x71: es1371->dac[0].vf = (es1371->dac[0].vf & ~0x1f8000) | ((val & 0xfc00) << 5); es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + es1371->dac[0].f_pos = 0; break; case 0x72: es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7fff) | (val & 0x7fff); @@ -501,6 +512,7 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0x75: es1371->dac[1].vf = (es1371->dac[1].vf & ~0x1f8000) | ((val & 0xfc00) << 5); es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + es1371->dac[1].f_pos = 0; break; case 0x76: es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7fff) | (val & 0x7fff); @@ -996,15 +1008,60 @@ static void es1371_fetch(es1371_t *es1371, int dac_nr) } } -static void es1371_next_sample(es1371_t *es1371, int dac_nr) +static inline float low_fir_es1371(int dac_nr, int i, float NewSample) { + static float x[2][2][128]; //input samples + static int x_pos[2] = {0, 0}; + float out = 0.0; + int read_pos; + int n_coef; + int pos = x_pos[dac_nr]; + + x[dac_nr][i][pos] = NewSample; + + /*Since only 1/16th of input samples are non-zero, only filter those that + are valid.*/ + read_pos = (pos + 15) & (127 & ~15); + n_coef = (16 - pos) & 15; + + while (n_coef < ES1371_NCoef) + { + out += low_fir_es1371_coef[n_coef] * x[dac_nr][i][read_pos]; + read_pos = (read_pos + 16) & (127 & ~15); + n_coef += 16; + } + + if (i == 1) + { + x_pos[dac_nr] = (x_pos[dac_nr] + 1) & 127; + if (x_pos[dac_nr] > 127) + x_pos[dac_nr] = 0; + } + + return out; +} + +static void es1371_next_sample_filtered(es1371_t *es1371, int dac_nr, int out_idx) +{ + int out_l, out_r; + int c; + if ((es1371->dac[dac_nr].buffer_pos - es1371->dac[dac_nr].buffer_pos_end) >= 0) { es1371_fetch(es1371, dac_nr); } - es1371->dac[dac_nr].out_l = es1371->dac[dac_nr].buffer_l[es1371->dac[dac_nr].buffer_pos & 63]; - es1371->dac[dac_nr].out_r = es1371->dac[dac_nr].buffer_r[es1371->dac[dac_nr].buffer_pos & 63]; + out_l = es1371->dac[dac_nr].buffer_l[es1371->dac[dac_nr].buffer_pos & 63]; + out_r = es1371->dac[dac_nr].buffer_r[es1371->dac[dac_nr].buffer_pos & 63]; + + es1371->dac[dac_nr].filtered_l[out_idx] = (int)low_fir_es1371(dac_nr, 0, (float)out_l); + es1371->dac[dac_nr].filtered_r[out_idx] = (int)low_fir_es1371(dac_nr, 1, (float)out_r); + for (c = 1; c < 16; c++) + { + es1371->dac[dac_nr].filtered_l[out_idx+c] = (int)low_fir_es1371(dac_nr, 0, 0); + es1371->dac[dac_nr].filtered_r[out_idx+c] = (int)low_fir_es1371(dac_nr, 1, 0); + } + // audiopci_log("Use %02x %04x %04x\n", es1371->dac[dac_nr].buffer_pos & 63, es1371->dac[dac_nr].out_l, es1371->dac[dac_nr].out_r); es1371->dac[dac_nr].buffer_pos++; @@ -1012,20 +1069,64 @@ static void es1371_next_sample(es1371_t *es1371, int dac_nr) } //static FILE *es1371_f;//,*es1371_f2; + +static void es1371_update(es1371_t *es1371) +{ + int32_t l, r; + + l = (es1371->dac[0].out_l * es1371->dac[0].vol_l) >> 12; + l += ((es1371->dac[1].out_l * es1371->dac[1].vol_l) >> 12); + r = (es1371->dac[0].out_r * es1371->dac[0].vol_r) >> 12; + r += ((es1371->dac[1].out_r * es1371->dac[1].vol_r) >> 12); + + l >>= 1; + r >>= 1; + + l = (l * es1371->master_vol_l) >> 15; + r = (r * es1371->master_vol_r) >> 15; + + if (l < -32768) + l = -32768; + else if (l > 32767) + l = 32767; + if (r < -32768) + r = -32768; + else if (r > 32767) + r = 32767; + + for (; es1371->pos < sound_pos_global; es1371->pos++) + { + es1371->buffer[es1371->pos*2] = l; + es1371->buffer[es1371->pos*2 + 1] = r; + } +} + static void es1371_poll(void *p) { es1371_t *es1371 = (es1371_t *)p; es1371->dac[1].time += es1371->dac[1].latch; + es1371_update(es1371); + if (es1371->int_ctrl & INT_DAC1_EN) { + int frac = es1371->dac[0].ac & 0x7fff; + int idx = es1371->dac[0].ac >> 15; + int samp1_l = es1371->dac[0].filtered_l[idx]; + int samp1_r = es1371->dac[0].filtered_r[idx]; + int samp2_l = es1371->dac[0].filtered_l[(idx + 1) & 31]; + int samp2_r = es1371->dac[0].filtered_r[(idx + 1) & 31]; + + es1371->dac[0].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; + es1371->dac[0].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; // audiopci_log("1Samp %i %i %08x\n", es1371->dac[0].curr_samp_ct, es1371->dac[0].samp_ct, es1371->dac[0].ac); - es1371->dac[0].ac += es1371->dac[0].vf; - if (es1371->dac[0].ac & (~0 << (15+4))) + es1371->dac[0].ac += es1371->dac[0].vf; + es1371->dac[0].ac &= ((32 << 15) - 1); + if ((es1371->dac[0].ac >> (15+4)) != es1371->dac[0].f_pos) { - es1371->dac[0].ac &= ~(~0 << (15+4)); - es1371_next_sample(es1371, 0); + es1371_next_sample_filtered(es1371, 0, es1371->dac[0].f_pos ? 16 : 0); + es1371->dac[0].f_pos = (es1371->dac[0].f_pos + 1) & 1; es1371->dac[0].curr_samp_ct++; if (es1371->dac[0].curr_samp_ct == es1371->dac[0].samp_ct) @@ -1043,51 +1144,35 @@ static void es1371_poll(void *p) if (es1371->int_ctrl & INT_DAC2_EN) { + int frac = es1371->dac[1].ac & 0x7fff; + int idx = es1371->dac[1].ac >> 15; + int samp1_l = es1371->dac[1].filtered_l[idx]; + int samp1_r = es1371->dac[1].filtered_r[idx]; + int samp2_l = es1371->dac[1].filtered_l[(idx + 1) & 31]; + int samp2_r = es1371->dac[1].filtered_r[(idx + 1) & 31]; + + es1371->dac[1].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; + es1371->dac[1].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; // audiopci_log("2Samp %i %i %08x\n", es1371->dac[1].curr_samp_ct, es1371->dac[1].samp_ct, es1371->dac[1].ac); es1371->dac[1].ac += es1371->dac[1].vf; - if (es1371->dac[1].ac & (~0 << (15+4))) + es1371->dac[1].ac &= ((32 << 15) - 1); + if ((es1371->dac[1].ac >> (15+4)) != es1371->dac[1].f_pos) { - es1371->dac[1].ac &= ~(~0 << (15+4)); - es1371_next_sample(es1371, 1); + es1371_next_sample_filtered(es1371, 1, es1371->dac[1].f_pos ? 16 : 0); + es1371->dac[1].f_pos = (es1371->dac[1].f_pos + 1) & 1; es1371->dac[1].curr_samp_ct++; if (es1371->dac[1].curr_samp_ct > es1371->dac[1].samp_ct) { - es1371->dac[1].curr_samp_ct = 0; +// es1371->dac[1].curr_samp_ct = 0; // audiopci_log("DAC2 IRQ\n"); es1371->int_status |= INT_STATUS_DAC2; es1371_update_irqs(es1371); } + if (es1371->dac[1].curr_samp_ct > es1371->dac[1].samp_ct) + es1371->dac[1].curr_samp_ct = 0; } } - - for (; es1371->pos < sound_pos_global; es1371->pos++) - { - int32_t l, r; - - l = (es1371->dac[0].out_l * es1371->dac[0].vol_l) >> 12; - l += ((es1371->dac[1].out_l * es1371->dac[1].vol_l) >> 12); - r = (es1371->dac[0].out_r * es1371->dac[0].vol_r) >> 12; - r += ((es1371->dac[1].out_r * es1371->dac[1].vol_r) >> 12); - - l >>= 1; - r >>= 1; - - l = (l * es1371->master_vol_l) >> 15; - r = (r * es1371->master_vol_r) >> 15; - - if (l < -32768) - l = -32768; - else if (l > 32767) - l = 32767; - if (r < -32768) - r = -32768; - else if (r > 32767) - r = 32767; - - es1371->buffer[es1371->pos*2] = l; - es1371->buffer[es1371->pos*2 + 1] = r; - } } static void es1371_get_buffer(int32_t *buffer, int len, void *p) @@ -1095,12 +1180,48 @@ static void es1371_get_buffer(int32_t *buffer, int len, void *p) es1371_t *es1371 = (es1371_t *)p; int c; + es1371_update(es1371); + for (c = 0; c < len * 2; c++) buffer[c] += (es1371->buffer[c] / 2); es1371->pos = 0; } +static inline double sinc(double x) +{ + return sin(M_PI * x) / (M_PI * x); +} + +static void generate_es1371_filter() +{ + /*Cutoff frequency = 1 / 32*/ + float fC = 1.0 / 32.0; + float gain; + int n; + + for (n = 0; n < ES1371_NCoef; n++) + { + /*Blackman window*/ + double w = 0.42 - (0.5 * cos((2.0*n*M_PI)/(double)(ES1371_NCoef-1))) + (0.08 * cos((4.0*n*M_PI)/(double)(ES1371_NCoef-1))); + /*Sinc filter*/ + double h = sinc(2.0 * fC * ((double)n - ((double)(ES1371_NCoef-1) / 2.0))); + + /*Create windowed-sinc filter*/ + low_fir_es1371_coef[n] = w * h; + } + + low_fir_es1371_coef[(ES1371_NCoef - 1) / 2] = 1.0; + + gain = 0.0; + for (n = 0; n < ES1371_NCoef; n++) + gain += low_fir_es1371_coef[n] / (float)N; + + /*Normalise filter, to produce unity gain*/ + for (n = 0; n < ES1371_NCoef; n++) + low_fir_es1371_coef[n] /= gain; +} + static void *es1371_init() { es1371_t *es1371 = malloc(sizeof(es1371_t)); @@ -1111,6 +1232,8 @@ static void *es1371_init() es1371->card = pci_add_card(PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371); timer_add(es1371_poll, &es1371->dac[1].time, TIMER_ALWAYS_ENABLED, es1371); + + generate_es1371_filter(); return es1371; } @@ -1128,6 +1251,54 @@ static void es1371_speed_changed(void *p) es1371->dac[1].latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); } + +void es1371_add_status_info_dac(es1371_t *es1371, char *s, int max_len, int dac_nr) +{ + int ena = dac_nr ? INT_DAC2_EN : INT_DAC1_EN; + char *dac_name = dac_nr ? "DAC2 (Wave)" : "DAC1 (MIDI)"; + char temps[128]; + + if (es1371->int_ctrl & ena) + { + int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3); + double freq = 48000.0 * ((double)es1371->dac[dac_nr].vf / (32768.0 * 16.0)); + + switch (format) + { + case FORMAT_MONO_8: + snprintf(temps, 128, "%s format : 8-bit mono\n", dac_name); + break; + case FORMAT_STEREO_8: + snprintf(temps, 128, "%s format : 8-bit stereo\n", dac_name); + break; + case FORMAT_MONO_16: + snprintf(temps, 128, "%s format : 16-bit mono\n", dac_name); + break; + case FORMAT_STEREO_16: + snprintf(temps, 128, "%s format : 16-bit stereo\n", dac_name); + break; + } + + strncat(s, temps, max_len); + max_len -= strlen(temps); + + snprintf(temps, 128, "Playback frequency : %i Hz\n", (int)freq); + strncat(s, temps, max_len); + } + else + { + snprintf(temps, max_len, "%s stopped\n", dac_name); + strncat(s, temps, max_len); + } +} + +void es1371_add_status_info(char *s, int max_len, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + es1371_add_status_info_dac(es1371, s, max_len, 0); + es1371_add_status_info_dac(es1371, s, max_len, 1); +} device_t es1371_device = { @@ -1140,6 +1311,6 @@ device_t es1371_device = NULL, es1371_speed_changed, NULL, - NULL, + es1371_add_status_info, NULL }; From 7ce6d6d4ed28b7d2ede60bd1fbe379696739140b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 15 Mar 2018 23:24:04 +0100 Subject: [PATCH 16/23] (nw) --- src/video/vid_ati_mach64.c | 170 +++++++++++++++++-------------------- src/video/vid_svga.c | 2 +- 2 files changed, 79 insertions(+), 93 deletions(-) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index d8478bfdf..255aa43f4 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -8,7 +8,7 @@ * * ATi Mach64 graphics card emulation. * - * Version: @(#)vid_ati_mach64.c 1.0.15 2018/03/13 + * Version: @(#)vid_ati_mach64.c 1.0.13 2018/03/02 * * Authors: Sarah Walker, * Miran Grca, @@ -174,6 +174,7 @@ typedef struct mach64_t uint32_t linear_base, old_linear_base; uint32_t io_base; + int draw_pixel; struct { @@ -290,6 +291,7 @@ enum { SRC_PATT_EN = 1, SRC_PATT_ROT_EN = 2, + SRC_BYTE_ALIGN = 3, SRC_LINEAR_EN = 4 }; @@ -457,33 +459,38 @@ void mach64_recalctimings(svga_t *svga) switch ((mach64->crtc_gen_cntl >> 8) & 7) { case 1: + mach64->draw_pixel = 4; if (mach64->type != MACH64_GX) svga->render = svga_render_4bpp_highres; svga->hdisp *= 8; break; - case 2: + case 2: + mach64->draw_pixel = 8; if (mach64->type != MACH64_GX) svga->render = svga_render_8bpp_highres; svga->hdisp *= 8; svga->rowoffset /= 2; break; - case 3: + case 3: + mach64->draw_pixel = 16; if (mach64->type != MACH64_GX) svga->render = svga_render_15bpp_highres; svga->hdisp *= 8; break; - case 4: + case 4: + mach64->draw_pixel = 16; if (mach64->type != MACH64_GX) svga->render = svga_render_16bpp_highres; svga->hdisp *= 8; break; - case 5: + case 5: if (mach64->type != MACH64_GX) svga->render = svga_render_24bpp_highres; svga->hdisp *= 8; svga->rowoffset = (svga->rowoffset * 3) / 2; break; - case 6: + case 6: + mach64->draw_pixel = 32; if (mach64->type != MACH64_GX) svga->render = svga_render_32bpp_highres; svga->hdisp *= 8; @@ -643,11 +650,7 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val (addr & 0x3ff) == 0x113) && !(val & 0x80)) { mach64_start_fill(mach64); -#ifdef MACH64_DEBUG - pclog("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), - ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), - (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src); -#endif + if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) @@ -863,7 +866,9 @@ static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t if (mach64->accel.source_host || (mach64->dp_pix_width & DP_BYTE_PIX_ORDER)) mach64_blit(val, 32, mach64); else + { mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32, mach64); + } break; default: @@ -950,29 +955,36 @@ void mach64_cursor_dump(mach64_t *mach64) void mach64_start_fill(mach64_t *mach64) { - int x, y; - + int x, y; + mach64->accel.dst_x = 0; mach64->accel.dst_y = 0; mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff; mach64->accel.dst_y_start = mach64->dst_y_x & 0xfff; mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; - mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; + mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; - if (((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC) - { - if (mach64->accel.dst_width & 7) - mach64->accel.dst_width = (mach64->accel.dst_width & ~7) + 8; - } +/* + if ((((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC)) + { + pclog("Byte Align set=%02x\n", mach64->dp_pix_width & DP_BYTE_PIX_ORDER); + } +*/ + + if (((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC) + { + if (mach64->accel.dst_width & 7) + mach64->accel.dst_width = (mach64->accel.dst_width & ~7) + 8; + } + + mach64->accel.x_count = mach64->accel.dst_width; - mach64->accel.x_count = mach64->accel.dst_width; - - mach64->accel.src_x = 0; - mach64->accel.src_y = 0; + mach64->accel.src_x = 0; + mach64->accel.src_y = 0; mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; mach64->accel.src_y_start = mach64->src_y_x & 0xfff; - if (mach64->src_cntl & SRC_LINEAR_EN) + if (mach64->src_cntl & (SRC_LINEAR_EN|SRC_BYTE_ALIGN)) mach64->accel.src_x_count = 0x7ffffff; /*Essentially infinite*/ else mach64->accel.src_x_count = (mach64->src_height1_width1 >> 16) & 0x7fff; @@ -985,18 +997,9 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff; mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; - -#ifdef MACH64_DEBUG - pclog("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count, - mach64->accel.src_y_count, - mach64->accel.src_width1, - mach64->accel.src_height1, - mach64->src_height1_width1, - mach64->src_height2_width2); -#endif - + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; - mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; @@ -1006,18 +1009,18 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.source_bg = mach64->dp_src & 7; mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; - mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; - + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; - + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; if (mach64->accel.src_size == WIDTH_1BIT) - mach64->accel.src_offset <<= 3; + mach64->accel.src_offset <<= 3; else mach64->accel.src_offset >>= mach64->accel.src_size; @@ -1027,7 +1030,7 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.dst_offset >>= mach64->accel.dst_size; mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; - mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); @@ -1046,9 +1049,6 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; -/* mach64->accel.sc_left *= mach64_inc[mach64->accel.dst_pix_width]; - mach64->accel.sc_right *= mach64_inc[mach64->accel.dst_pix_width];*/ - mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; @@ -1060,16 +1060,13 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.poly_draw = 0; mach64->accel.busy = 1; -#ifdef MACH64_DEBUG - pclog("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); -#endif mach64->accel.op = OP_RECT; } void mach64_start_line(mach64_t *mach64) { - int x, y; - + int x, y; + mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff; mach64->accel.dst_y = mach64->dst_y_x & 0xfff; @@ -1092,7 +1089,7 @@ void mach64_start_line(mach64_t *mach64) mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; - + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; @@ -1107,9 +1104,6 @@ void mach64_start_line(mach64_t *mach64) else mach64->accel.dst_offset >>= mach64->accel.dst_size; -/* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; - mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ - mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); for (y = 0; y < 8; y++) @@ -1138,23 +1132,25 @@ void mach64_start_line(mach64_t *mach64) mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); mach64->accel.busy = 1; -#ifdef MACH64_DEBUG - pclog("mach64_start_line\n"); -#endif mach64->accel.op = OP_LINE; } -#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ - else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ - else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ - else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; \ - else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; - +#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ + else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ + else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ + else \ + { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (((addr) & 7))) & 1; \ + else \ + dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; \ + } + #define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ { \ case 0x0: dest_dat = ~dest_dat; break; \ case 0x1: dest_dat = 0; break; \ - case 0x2: dest_dat = 0xffffffff; break; \ + case 0x2: dest_dat = ~0; break; \ case 0x3: dest_dat = dest_dat; break; \ case 0x4: dest_dat = ~src_dat; break; \ case 0x5: dest_dat = src_dat ^ dest_dat; break; \ @@ -1169,7 +1165,7 @@ void mach64_start_line(mach64_t *mach64) case 0xe: dest_dat = ~src_dat & dest_dat; break; \ case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ } - + #define WRITE(addr, width) if (width == 0) \ { \ svga->vram[(addr) & mach64->vram_mask] = dest_dat; \ @@ -1187,17 +1183,10 @@ void mach64_start_line(mach64_t *mach64) } \ else \ { \ - if (dest_dat & 1) { \ - if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ - svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \ - else \ - svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (7 - ((addr) & 7)); \ - } else { \ - if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ - svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \ - else \ - svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (7 - ((addr) & 7)));\ - } \ + if (dest_dat & 1) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (((addr) & 7)); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (((addr) & 7))); \ svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \ } @@ -1225,7 +1214,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; int src_x; int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff; - + if (mach64->src_cntl & SRC_LINEAR_EN) src_x = mach64->accel.src_x; else @@ -1273,27 +1262,24 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mix = 1; break; case MONO_SRC_BLITSRC: - if (mach64->src_cntl & SRC_LINEAR_EN) - { - READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); - } - else - { - READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); - } + if (mach64->src_cntl & SRC_LINEAR_EN) { + READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); + } else { + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); + } break; } if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right && dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom) - { + { switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) { case SRC_HOST: src_dat = host_dat; break; case SRC_BLITSRC: - READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); break; case SRC_FG: src_dat = mach64->accel.dp_frgd_clr; @@ -1341,7 +1327,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16); mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16); } - + mach64->accel.src_x += mach64->accel.xinc; mach64->accel.dst_x += mach64->accel.xinc; if (!(mach64->src_cntl & SRC_LINEAR_EN)) @@ -1360,6 +1346,8 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) } } + + mach64->accel.x_count--; if (mach64->accel.x_count <= 0) @@ -1391,19 +1379,17 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mach64->accel.poly_draw = 0; mach64->accel.dst_height--; - + if (mach64->accel.dst_height <= 0) { /*Blit finished*/ -#ifdef MACH64_DEBUG - pclog("mach64 blit finished\n"); -#endif mach64->accel.busy = 0; if (mach64->dst_cntl & DST_X_TILE) mach64->dst_y_x = (mach64->dst_y_x & 0xfff) | ((mach64->dst_y_x + (mach64->accel.dst_width << 16)) & 0xfff0000); if (mach64->dst_cntl & DST_Y_TILE) mach64->dst_y_x = (mach64->dst_y_x & 0xfff0000) | ((mach64->dst_y_x + (mach64->dst_height_width & 0x1fff)) & 0xfff); - return; + + return; } if (mach64->host_cntl & HOST_BYTE_ALIGN) { @@ -2018,7 +2004,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) mach64_wait_fifo_idle(mach64); READ8(addr, mach64->dp_frgd_clr); break; - + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->dp_pix_width); diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 92b17be32..92de3df80 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -69,7 +69,7 @@ void svga_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3C0: - case 0x3C1: + case 0x3C1: if (!svga->attrff) { svga->attraddr = val & 31; From 1f11f9f9a145f74fb8bc8e43b4eeb6ca36f876b8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 15 Mar 2018 23:32:07 +0100 Subject: [PATCH 17/23] IDE buffers are now allocated on IDE reset, only for attached devices (and sector buffers only for hard disks). --- src/disk/hdc_ide.c | 50 ++++++++++++++++++++++++++++++++++++++-------- src/disk/hdc_ide.h | 7 ++++--- src/pc.c | 4 +++- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 3d572d035..b2743528b 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.33 2018/03/15 + * Version: @(#)hdc_ide.c 1.0.34 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -20,10 +20,11 @@ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE +#include #include #include +#include #include -#include #include #include #define HAVE_STDARG_H @@ -793,6 +794,24 @@ void ide_ter_disable_cond(); void ide_qua_disable_cond(); +void ide_destroy_buffers(void) +{ + int d; + + for (d = 0; d < (IDE_NUM+XTIDE_NUM); d++) + { + if (ide_drives[d].buffer) { + free(ide_drives[d].buffer); + ide_drives[d].buffer = NULL; + } + + if (ide_drives[d].sector_buffer) { + free(ide_drives[d].sector_buffer); + ide_drives[d].sector_buffer = NULL; + } + } +} + void ide_reset(void) { int c, d; @@ -818,8 +837,18 @@ void ide_reset(void) ide_drives[d].atastat = READY_STAT | DSC_STAT; ide_drives[d].service = 0; ide_drives[d].board = d >> 1; + + if (ide_drives[d].buffer) { + free(ide_drives[d].buffer); + ide_drives[d].buffer = NULL; + } + + if (ide_drives[d].sector_buffer) { + free(ide_drives[d].sector_buffer); + ide_drives[d].sector_buffer = NULL; + } } - + idecallback[0]=idecallback[1]=0LL; idecallback[2]=idecallback[3]=0LL; idecallback[4]=0LL; @@ -832,12 +861,16 @@ void ide_reset(void) { ide_log("Found IDE hard disk on channel %i\n", hdd[d].ide_channel); loadhd(&ide_drives[hdd[d].ide_channel], d, hdd[d].fn); + ide_drives[hdd[d].ide_channel].sector_buffer = NULL; /* Important, makes sure malloc does not reuse an existing pointer from elsewhere. */ + ide_drives[hdd[d].ide_channel].sector_buffer = (uint8_t *) malloc(256*512); if (++c >= (IDE_NUM+XTIDE_NUM)) break; } if ((hdd[d].bus==HDD_BUS_XTIDE) && (hdd[d].xtide_channel < XTIDE_NUM)) { ide_log("Found XT IDE hard disk on channel %i\n", hdd[d].xtide_channel); loadhd(&ide_drives[hdd[d].xtide_channel | 8], d, hdd[d].fn); + ide_drives[hdd[d].xtide_channel | 8].sector_buffer = NULL; /* Important, makes sure malloc does not reuse an existing pointer from elsewhere. */ + ide_drives[hdd[d].xtide_channel | 8].sector_buffer = (uint8_t *) malloc(256*512); if (++c >= (IDE_NUM+XTIDE_NUM)) break; } } @@ -845,13 +878,14 @@ void ide_reset(void) for (d = 0; d < IDE_NUM; d++) { - if (ide_drive_is_zip(&ide_drives[d]) && (ide_drives[d].type != IDE_HDD)) - { + if (ide_drive_is_zip(&ide_drives[d]) && (ide_drives[d].type == IDE_NONE)) ide_drives[d].type = IDE_ZIP; - } - else if (ide_drive_is_cdrom(&ide_drives[d]) && (ide_drives[d].type != IDE_HDD)) - { + else if (ide_drive_is_cdrom(&ide_drives[d]) && (ide_drives[d].type == IDE_NONE)) ide_drives[d].type = IDE_CDROM; + + if (ide_drives[d].type != IDE_NONE) { + ide_drives[d].buffer = NULL; /* Important, makes sure malloc does not reuse an existing pointer from elsewhere. */ + ide_drives[d].buffer = (uint16_t *) malloc(65536); } ide_set_signature(&ide_drives[d]); diff --git a/src/disk/hdc_ide.h b/src/disk/hdc_ide.h index ce3cd8436..74e938b2e 100644 --- a/src/disk/hdc_ide.h +++ b/src/disk/hdc_ide.h @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdd_ide.h 1.0.6 2018/02/14 + * Version: @(#)hdd_ide.h 1.0.7 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -36,7 +36,7 @@ typedef struct { int packetstatus; uint8_t asc; int reset; - uint16_t buffer[65536]; + uint16_t *buffer; int irqstat; int service; int lba; @@ -49,7 +49,7 @@ typedef struct { int hdd_num; uint8_t specify_success; int mdma_mode; - uint8_t sector_buffer[256*512]; + uint8_t *sector_buffer; int do_initial_read; int sector_pos; } IDE; @@ -104,6 +104,7 @@ extern void ide_set_callback(uint8_t channel, int64_t callback); extern void secondary_ide_check(void); extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src); +extern void ide_destroy_buffers(void); extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length); extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length); diff --git a/src/pc.c b/src/pc.c index 8ec023651..3aec78258 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.63 2018/03/13 + * Version: @(#)pc.c 1.0.64 2018/03/15 * * Authors: Sarah Walker, * Miran Grca, @@ -968,6 +968,8 @@ pc_close(thread_t *ptr) sound_cd_thread_end(); mem_destroy_pages(); + + ide_destroy_buffers(); } From 78515537efb7791ad8a448d69bd08916d31bb8cd Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 16 Mar 2018 00:08:43 +0100 Subject: [PATCH 18/23] Changed the way PS/2 Model 80 split mapping is handled (but OS/2 2.x still runs on it); The pages array are no longer allocated for the entire memory of space if memory size + 384 is above 16 MB (turns out it was not needed at all), further significantly reduces the emulator's RAM usage; Made greatpsycho's revised SVGA status handling specific to ATI cards, while the generic (S)VGA code uses the old handling - fixes error 2401 on PS/2 Model 80. --- src/machine/m_ps2_mca.c | 63 +++++++++++++++++++++++++++++--- src/mem.c | 75 ++++---------------------------------- src/mem.h | 3 -- src/video/vid_ati18800.c | 35 +++++++++++++++++- src/video/vid_ati28800.c | 35 +++++++++++++++++- src/video/vid_ati_mach64.c | 35 +++++++++++++++++- src/video/vid_svga.c | 34 +---------------- 7 files changed, 167 insertions(+), 113 deletions(-) diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index e9c74935a..f85a06c0b 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -40,8 +40,9 @@ static struct uint8_t io_id; mem_mapping_t shadow_mapping; + mem_mapping_t split_mapping; mem_mapping_t expansion_mapping; - mem_mapping_t cache_mapping; + mem_mapping_t cache_mapping; uint8_t (*planar_read)(uint16_t port); void (*planar_write)(uint16_t port, uint8_t val); @@ -49,11 +50,12 @@ static struct uint8_t mem_regs[3]; uint32_t split_addr, split_size; + uint32_t split_phys; uint8_t mem_pos_regs[8]; uint8_t mem_2mb_pos_regs[8]; - int pending_cache_miss; + int pending_cache_miss; } ps2; /*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any @@ -173,6 +175,37 @@ static void ps2_write_shadow_raml(uint32_t addr, uint32_t val, void *priv) mem_write_raml(addr, val, priv); } +static uint8_t ps2_read_split_ram(uint32_t addr, void *priv) +{ + addr = (addr % (ps2.split_size << 10)) + ps2.split_phys; + return mem_read_ram(addr, priv); +} +static uint16_t ps2_read_split_ramw(uint32_t addr, void *priv) +{ + addr = (addr % (ps2.split_size << 10)) + ps2.split_phys; + return mem_read_ramw(addr, priv); +} +static uint32_t ps2_read_split_raml(uint32_t addr, void *priv) +{ + addr = (addr % (ps2.split_size << 10)) + ps2.split_phys; + return mem_read_raml(addr, priv); +} +static void ps2_write_split_ram(uint32_t addr, uint8_t val, void *priv) +{ + addr = (addr % (ps2.split_size << 10)) + ps2.split_phys; + mem_write_ram(addr, val, priv); +} +static void ps2_write_split_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addr = (addr % (ps2.split_size << 10)) + ps2.split_phys; + mem_write_ramw(addr, val, priv); +} +static void ps2_write_split_raml(uint32_t addr, uint32_t val, void *priv) +{ + addr = (addr % (ps2.split_size << 10)) + ps2.split_phys; + mem_write_raml(addr, val, priv); +} + #define PS2_SETUP_IO 0x80 #define PS2_SETUP_VGA 0x20 @@ -839,7 +872,7 @@ static void ps2_mca_board_model_55sx_init() static void mem_encoding_update() { - mem_split_disable(ps2.split_size, ps2.split_addr); + mem_mapping_disable(&ps2.split_mapping); ps2.split_addr = ((uint32_t) (ps2.mem_regs[0] & 0xf)) << 20; @@ -861,12 +894,16 @@ static void mem_encoding_update() if (!(ps2.mem_regs[1] & 8)) { - if (ps2.mem_regs[1] & 4) + if (ps2.mem_regs[1] & 4) { ps2.split_size = 384; - else + ps2.split_phys = 0x80000; + } else { ps2.split_size = 256; + ps2.split_phys = 0xa0000; + } - mem_split_enable(ps2.split_size, ps2.split_addr); + mem_mapping_set_exec(&ps2.split_mapping, &ram[ps2.split_phys]); + mem_mapping_set_addr(&ps2.split_mapping, ps2.split_addr, ps2.split_size << 10); /* pclog("PS/2 Model 80-111: Split memory block enabled at %08X\n", ps2.split_addr); */ } /* else { @@ -1108,6 +1145,20 @@ static void ps2_mca_board_model_80_type2_init(int is486) ps2.mem_regs[0] |= ((mem_size/1024) & 0x0f); + mem_mapping_add(&ps2.split_mapping, + (mem_size+256) * 1024, + 256*1024, + ps2_read_split_ram, + ps2_read_split_ramw, + ps2_read_split_raml, + ps2_write_split_ram, + ps2_write_split_ramw, + ps2_write_split_raml, + &ram[0xa0000], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.split_mapping); + if ((mem_size > 4096) && !is486) { /* Only 4 MB supported on planar, create a memory expansion card for the rest */ diff --git a/src/mem.c b/src/mem.c index 7bb2a12bc..cbd3fe165 100644 --- a/src/mem.c +++ b/src/mem.c @@ -1334,13 +1334,16 @@ void mem_resize_pages(void) if (AT) { if (cpu_16bitbus) total_size = 4096; - else - total_size = 1048576; + else { + total_size = (mem_size + 384) >> 2; + if ((total_size << 2) < (mem_size + 384)) + total_size++; + if (total_size < 4096) + total_size = 4096; + } } else total_size = 256; - pclog("%i pages\n", total_size); - pages = malloc(total_size * sizeof(page_t)); memset(pages, 0, total_size * sizeof(page_t)); @@ -1469,70 +1472,6 @@ void mem_remap_top_384k() mem_remap_top(384); } -void mem_split_enable(int max_size, uint32_t addr) -{ - int c; - - uint8_t *mem_split_buffer = &ram[0x80000]; - - if (split_mapping_enabled) - return; - -#if 0 - pclog("Split mapping enable at %08X\n", addr); -#endif - - mem_set_mem_state(addr, max_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_set_addr(&ram_split_mapping, addr, max_size * 1024); - mem_mapping_set_exec(&ram_split_mapping, &ram[addr]); - - if (max_size == 384) - memcpy(&ram[addr], mem_split_buffer, max_size); - else - memcpy(&ram[addr], &mem_split_buffer[128 * 1024], max_size); - - for (c = ((addr / 1024) / 64); c < (((addr / 1024) + max_size - 1) / 64); c++) - { - isram[c] = 1; - } - - flushmmucache(); - - split_mapping_enabled = 1; -} - -void mem_split_disable(int max_size, uint32_t addr) -{ - int c; - - uint8_t *mem_split_buffer = &ram[0x80000]; - - if (!split_mapping_enabled) - return; - -#if 0 - pclog("Split mapping disable at %08X\n", addr); -#endif - - if (max_size == 384) - memcpy(mem_split_buffer, &ram[addr], max_size); - else - memcpy(&mem_split_buffer[128 * 1024], &ram[addr], max_size); - - mem_mapping_disable(&ram_split_mapping); - mem_set_mem_state(addr, max_size * 1024, 0); - mem_mapping_set_exec(&ram_split_mapping, NULL); - - for (c = ((addr / 1024) / 64); c < (((addr / 1024) + max_size - 1) / 64); c++) - { - isram[c] = 0; - } - - flushmmucache(); - - split_mapping_enabled = 0; -} - void mem_resize() { int c; diff --git a/src/mem.h b/src/mem.h index e31b3b1b2..f7f488435 100644 --- a/src/mem.h +++ b/src/mem.h @@ -231,9 +231,6 @@ extern void flushmmucache_cr3(void); extern void flushmmucache_nopc(void); extern void mmu_invalidate(uint32_t addr); -extern void mem_split_enable(int max_size, uint32_t addr); -extern void mem_split_disable(int max_size, uint32_t addr); - extern void mem_add_bios(void); diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index 3c047dc7d..2081f0786 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -8,7 +8,7 @@ * * ATI 18800 emulation (VGA Edge-16) * - * Version: @(#)vid_ati18800.c 1.0.6 2018/03/15 + * Version: @(#)vid_ati18800.c 1.0.7 2018/03/16 * * Authors: Sarah Walker, * Miran Grca, @@ -150,6 +150,39 @@ static uint8_t ati18800_in(uint16_t addr, void *p) case 0x3D5: temp = svga->crtc[svga->crtcreg]; break; + case 0x3DA: + svga->attrff = 0; + svga->attrff = 0; + svga->cgastat &= ~0x30; + /* copy color diagnostic info from the overscan color register */ + switch (svga->attrregs[0x12] & 0x30) + { + case 0x00: /* P0 and P2 */ + if (svga->attrregs[0x11] & 0x01) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x04) + svga->cgastat |= 0x20; + break; + case 0x10: /* P4 and P5 */ + if (svga->attrregs[0x11] & 0x10) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x20) + svga->cgastat |= 0x20; + break; + case 0x20: /* P1 and P3 */ + if (svga->attrregs[0x11] & 0x02) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x08) + svga->cgastat |= 0x20; + break; + case 0x30: /* P6 and P7 */ + if (svga->attrregs[0x11] & 0x40) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x80) + svga->cgastat |= 0x20; + break; + } + return svga->cgastat; default: temp = svga_in(addr, svga); break; diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index 7c6b64a51..0a1a0337d 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -8,7 +8,7 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * Version: @(#)vid_ati28800.c 1.0.11 2018/03/15 + * Version: @(#)vid_ati28800.c 1.0.12 2018/03/16 * * Authors: Sarah Walker, * Miran Grca, @@ -246,6 +246,39 @@ static uint8_t ati28800_in(uint16_t addr, void *p) case 0x3D5: temp = svga->crtc[svga->crtcreg]; break; + case 0x3DA: + svga->attrff = 0; + svga->attrff = 0; + svga->cgastat &= ~0x30; + /* copy color diagnostic info from the overscan color register */ + switch (svga->attrregs[0x12] & 0x30) + { + case 0x00: /* P0 and P2 */ + if (svga->attrregs[0x11] & 0x01) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x04) + svga->cgastat |= 0x20; + break; + case 0x10: /* P4 and P5 */ + if (svga->attrregs[0x11] & 0x10) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x20) + svga->cgastat |= 0x20; + break; + case 0x20: /* P1 and P3 */ + if (svga->attrregs[0x11] & 0x02) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x08) + svga->cgastat |= 0x20; + break; + case 0x30: /* P6 and P7 */ + if (svga->attrregs[0x11] & 0x40) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x80) + svga->cgastat |= 0x20; + break; + } + return svga->cgastat; default: temp = svga_in(addr, svga); break; diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index d8478bfdf..3b349c635 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -8,7 +8,7 @@ * * ATi Mach64 graphics card emulation. * - * Version: @(#)vid_ati_mach64.c 1.0.15 2018/03/13 + * Version: @(#)vid_ati_mach64.c 1.0.16 2018/03/16 * * Authors: Sarah Walker, * Miran Grca, @@ -429,6 +429,39 @@ uint8_t mach64_in(uint16_t addr, void *p) if (svga->crtcreg > 0x18) return 0xff; return svga->crtc[svga->crtcreg]; + case 0x3DA: + svga->attrff = 0; + svga->attrff = 0; + svga->cgastat &= ~0x30; + /* copy color diagnostic info from the overscan color register */ + switch (svga->attrregs[0x12] & 0x30) + { + case 0x00: /* P0 and P2 */ + if (svga->attrregs[0x11] & 0x01) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x04) + svga->cgastat |= 0x20; + break; + case 0x10: /* P4 and P5 */ + if (svga->attrregs[0x11] & 0x10) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x20) + svga->cgastat |= 0x20; + break; + case 0x20: /* P1 and P3 */ + if (svga->attrregs[0x11] & 0x02) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x08) + svga->cgastat |= 0x20; + break; + case 0x30: /* P6 and P7 */ + if (svga->attrregs[0x11] & 0x40) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x80) + svga->cgastat |= 0x20; + break; + } + return svga->cgastat; } return svga_in(addr, svga); } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 92b17be32..7299949b0 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,7 +11,7 @@ * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * - * Version: @(#)vid_svga.c 1.0.25 2018/03/12 + * Version: @(#)vid_svga.c 1.0.26 2018/03/16 * * Authors: Sarah Walker, * Miran Grca, @@ -295,43 +295,11 @@ uint8_t svga_in(uint16_t addr, void *p) svga->attrff = 0; svga->attrff = 0; - /* old diagnostic code if (svga->cgastat & 0x01) svga->cgastat &= ~0x30; else svga->cgastat ^= 0x30; return svga->cgastat; - */ - svga->cgastat &= ~0x30; - /* copy color diagnostic info from the overscan color register */ - switch (svga->attrregs[0x12] & 0x30) - { - case 0x00: /* P0 and P2 */ - if (svga->attrregs[0x11] & 0x01) - svga->cgastat |= 0x10; - if (svga->attrregs[0x11] & 0x04) - svga->cgastat |= 0x20; - break; - case 0x10: /* P4 and P5 */ - if (svga->attrregs[0x11] & 0x10) - svga->cgastat |= 0x10; - if (svga->attrregs[0x11] & 0x20) - svga->cgastat |= 0x20; - break; - case 0x20: /* P1 and P3 */ - if (svga->attrregs[0x11] & 0x02) - svga->cgastat |= 0x10; - if (svga->attrregs[0x11] & 0x08) - svga->cgastat |= 0x20; - break; - case 0x30: /* P6 and P7 */ - if (svga->attrregs[0x11] & 0x40) - svga->cgastat |= 0x10; - if (svga->attrregs[0x11] & 0x80) - svga->cgastat |= 0x20; - break; - } - return svga->cgastat; } return 0xFF; } From cb53faacb279e2a17f2c28a1a58822906ca1a6b1 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 16 Mar 2018 06:53:54 +0100 Subject: [PATCH 19/23] Fixed the IBM PS/2 Model 70 Type 3 and 4 ROM sizes. --- src/rom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rom.c b/src/rom.c index c36600291..19cf4c762 100644 --- a/src/rom.c +++ b/src/rom.c @@ -13,7 +13,7 @@ * - c386sx16 BIOS fails checksum * - the loadfont() calls should be done elsewhere * - * Version: @(#)rom.c 1.0.34 2018/03/11 + * Version: @(#)rom.c 1.0.35 2018/03/16 * * Authors: Sarah Walker, * Miran Grca, @@ -721,7 +721,7 @@ rom_load_bios(int rom_id) if (! rom_load_interleaved( L"roms/machines/ibmps2_m70_type3/70-a_even.bin", L"roms/machines/ibmps2_m70_type3/70-a_odd.bin", - 0x000000, 65536, 0, rom)) break; + 0x000000, 131072, 0, rom)) break; biosmask = 0x1ffff; return(1); @@ -729,7 +729,7 @@ rom_load_bios(int rom_id) if (! rom_load_interleaved( L"roms/machines/ibmps2_m70_type4/70-b_even.bin", L"roms/machines/ibmps2_m70_type4/70-b_odd.bin", - 0x000000, 65536, 0, rom)) break; + 0x000000, 131072, 0, rom)) break; biosmask = 0x1ffff; return(1); From a9cb339f23d8a268d64ed0526cae423a93a6b065 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 16 Mar 2018 15:30:25 +0100 Subject: [PATCH 20/23] Quick fix to the 24bit handling of the CL-GD5436 card. It actually fixes patterns in that mode. --- src/video/vid_cl54xx.c | 85 ++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 52 deletions(-) diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 09e70bbe6..e58e11a23 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -235,7 +235,6 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) case 0x12: svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; - svga->hwcursor.yoff = 0; if (val & CIRRUS_CURSOR_LARGE) svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); else @@ -1870,20 +1869,8 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) blt_mask *= 2; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) - { - x_max = 24; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) - { - blt_mask = (gd54xx->blt.mask & 0x1f); - blt_mask /= 3; - } - else - { - blt_mask = gd54xx->blt.mask & 7; - blt_mask *= 3; - } - } + blt_mask = (gd54xx->blt.mask & 0x1f); + x_max = 24; break; case CIRRUS_BLTMODE_PIXELWIDTH32: blt_mask = gd54xx->blt.mask & 7; @@ -1897,7 +1884,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; gd54xx->blt.width_backup = gd54xx->blt.width; gd54xx->blt.height_internal = gd54xx->blt.height; - gd54xx->blt.x_count = 0; + gd54xx->blt.x_count = 0; if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) gd54xx->blt.y_count = gd54xx->blt.src_addr & 7; else @@ -1963,19 +1950,16 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) } break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) + if ((gd54xx->blt.x_count % 3) == 2) + src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); + else if ((gd54xx->blt.x_count % 3) == 1) + src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); + else + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; + if ((gd54xx->blt.x_count % 3) == 2) { - if ((gd54xx->blt.x_count % 3) == 2) - src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); - else if ((gd54xx->blt.x_count % 3) == 1) - src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); - else - src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; - if ((gd54xx->blt.x_count % 3) == 2) - { - cpu_dat <<= 1; - count--; - } + cpu_dat <<= 1; + count--; } break; case CIRRUS_BLTMODE_PIXELWIDTH32: @@ -2012,8 +1996,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 24)]; + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 24)]; break; case CIRRUS_BLTMODE_PIXELWIDTH32: src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; @@ -2036,20 +2019,19 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) - { - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); - if ((gd54xx->blt.dst_addr % 3) == 2) - src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); - else if ((gd54xx->blt.dst_addr % 3) == 1) - src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); - else - src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; - } + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); + if ((gd54xx->blt.dst_addr % 3) == 2) + src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); + else if ((gd54xx->blt.dst_addr % 3) == 1) + src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); + else + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH32: mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); - if ((gd54xx->blt.dst_addr & 3) == 2) + if ((gd54xx->blt.dst_addr & 3) == 3) + src = mask ? (gd54xx->blt.fg_col >> 24) : (gd54xx->blt.bg_col >> 24); + else if ((gd54xx->blt.dst_addr & 3) == 2) src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); else if ((gd54xx->blt.dst_addr & 3) == 1) src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); @@ -2109,16 +2091,13 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) - { - mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); - if ((gd54xx->blt.dst_addr % 3) == 2) - src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); - else if ((gd54xx->blt.dst_addr % 3) == 1) - src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); - else - src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; - } + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); + if ((gd54xx->blt.dst_addr % 3) == 2) + src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); + else if ((gd54xx->blt.dst_addr % 3) == 1) + src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); + else + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH32: @@ -2176,7 +2155,9 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); gd54xx->blt.x_count++; - if (gd54xx->blt.x_count == x_max) { + + if (gd54xx->blt.x_count == x_max) + { gd54xx->blt.x_count = 0; if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == CIRRUS_BLTMODE_COLOREXPAND) gd54xx->blt.src_addr++; From 5c7afc7cded5d7a6757753fb78c7d07487d3b831 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 16 Mar 2018 15:33:16 +0100 Subject: [PATCH 21/23] Properly synced Mach64 source file. --- src/video/vid_ati_mach64.c | 168 ++++++++++++++++++++----------------- 1 file changed, 91 insertions(+), 77 deletions(-) diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 43ae476e4..3b349c635 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -174,7 +174,6 @@ typedef struct mach64_t uint32_t linear_base, old_linear_base; uint32_t io_base; - int draw_pixel; struct { @@ -291,7 +290,6 @@ enum { SRC_PATT_EN = 1, SRC_PATT_ROT_EN = 2, - SRC_BYTE_ALIGN = 3, SRC_LINEAR_EN = 4 }; @@ -492,38 +490,33 @@ void mach64_recalctimings(svga_t *svga) switch ((mach64->crtc_gen_cntl >> 8) & 7) { case 1: - mach64->draw_pixel = 4; if (mach64->type != MACH64_GX) svga->render = svga_render_4bpp_highres; svga->hdisp *= 8; break; - case 2: - mach64->draw_pixel = 8; + case 2: if (mach64->type != MACH64_GX) svga->render = svga_render_8bpp_highres; svga->hdisp *= 8; svga->rowoffset /= 2; break; - case 3: - mach64->draw_pixel = 16; + case 3: if (mach64->type != MACH64_GX) svga->render = svga_render_15bpp_highres; svga->hdisp *= 8; break; - case 4: - mach64->draw_pixel = 16; + case 4: if (mach64->type != MACH64_GX) svga->render = svga_render_16bpp_highres; svga->hdisp *= 8; break; - case 5: + case 5: if (mach64->type != MACH64_GX) svga->render = svga_render_24bpp_highres; svga->hdisp *= 8; svga->rowoffset = (svga->rowoffset * 3) / 2; break; - case 6: - mach64->draw_pixel = 32; + case 6: if (mach64->type != MACH64_GX) svga->render = svga_render_32bpp_highres; svga->hdisp *= 8; @@ -683,7 +676,11 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val (addr & 0x3ff) == 0x113) && !(val & 0x80)) { mach64_start_fill(mach64); - +#ifdef MACH64_DEBUG + pclog("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), + ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src); +#endif if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) @@ -899,9 +896,7 @@ static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t if (mach64->accel.source_host || (mach64->dp_pix_width & DP_BYTE_PIX_ORDER)) mach64_blit(val, 32, mach64); else - { mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32, mach64); - } break; default: @@ -988,36 +983,29 @@ void mach64_cursor_dump(mach64_t *mach64) void mach64_start_fill(mach64_t *mach64) { - int x, y; - + int x, y; + mach64->accel.dst_x = 0; mach64->accel.dst_y = 0; mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff; mach64->accel.dst_y_start = mach64->dst_y_x & 0xfff; mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; - mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; + mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; -/* - if ((((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC)) - { - pclog("Byte Align set=%02x\n", mach64->dp_pix_width & DP_BYTE_PIX_ORDER); - } -*/ - - if (((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC) - { - if (mach64->accel.dst_width & 7) - mach64->accel.dst_width = (mach64->accel.dst_width & ~7) + 8; - } - - mach64->accel.x_count = mach64->accel.dst_width; + if (((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC) + { + if (mach64->accel.dst_width & 7) + mach64->accel.dst_width = (mach64->accel.dst_width & ~7) + 8; + } - mach64->accel.src_x = 0; - mach64->accel.src_y = 0; + mach64->accel.x_count = mach64->accel.dst_width; + + mach64->accel.src_x = 0; + mach64->accel.src_y = 0; mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; mach64->accel.src_y_start = mach64->src_y_x & 0xfff; - if (mach64->src_cntl & (SRC_LINEAR_EN|SRC_BYTE_ALIGN)) + if (mach64->src_cntl & SRC_LINEAR_EN) mach64->accel.src_x_count = 0x7ffffff; /*Essentially infinite*/ else mach64->accel.src_x_count = (mach64->src_height1_width1 >> 16) & 0x7fff; @@ -1030,9 +1018,18 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff; mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; - + +#ifdef MACH64_DEBUG + pclog("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count, + mach64->accel.src_y_count, + mach64->accel.src_width1, + mach64->accel.src_height1, + mach64->src_height1_width1, + mach64->src_height2_width2); +#endif + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; - mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; @@ -1042,18 +1039,18 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.source_bg = mach64->dp_src & 7; mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; - mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; - + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; - + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; if (mach64->accel.src_size == WIDTH_1BIT) - mach64->accel.src_offset <<= 3; + mach64->accel.src_offset <<= 3; else mach64->accel.src_offset >>= mach64->accel.src_size; @@ -1063,7 +1060,7 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.dst_offset >>= mach64->accel.dst_size; mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; - mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); @@ -1082,6 +1079,9 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; +/* mach64->accel.sc_left *= mach64_inc[mach64->accel.dst_pix_width]; + mach64->accel.sc_right *= mach64_inc[mach64->accel.dst_pix_width];*/ + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; @@ -1093,13 +1093,16 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.poly_draw = 0; mach64->accel.busy = 1; +#ifdef MACH64_DEBUG + pclog("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); +#endif mach64->accel.op = OP_RECT; } void mach64_start_line(mach64_t *mach64) { - int x, y; - + int x, y; + mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff; mach64->accel.dst_y = mach64->dst_y_x & 0xfff; @@ -1122,7 +1125,7 @@ void mach64_start_line(mach64_t *mach64) mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; - + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; @@ -1137,6 +1140,9 @@ void mach64_start_line(mach64_t *mach64) else mach64->accel.dst_offset >>= mach64->accel.dst_size; +/* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); for (y = 0; y < 8; y++) @@ -1165,25 +1171,23 @@ void mach64_start_line(mach64_t *mach64) mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); mach64->accel.busy = 1; +#ifdef MACH64_DEBUG + pclog("mach64_start_line\n"); +#endif mach64->accel.op = OP_LINE; } -#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ - else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ - else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ - else \ - { \ - if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ - dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (((addr) & 7))) & 1; \ - else \ - dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; \ - } - +#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ + else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ + else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ + else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; \ + else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; + #define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ { \ case 0x0: dest_dat = ~dest_dat; break; \ case 0x1: dest_dat = 0; break; \ - case 0x2: dest_dat = ~0; break; \ + case 0x2: dest_dat = 0xffffffff; break; \ case 0x3: dest_dat = dest_dat; break; \ case 0x4: dest_dat = ~src_dat; break; \ case 0x5: dest_dat = src_dat ^ dest_dat; break; \ @@ -1198,7 +1202,7 @@ void mach64_start_line(mach64_t *mach64) case 0xe: dest_dat = ~src_dat & dest_dat; break; \ case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ } - + #define WRITE(addr, width) if (width == 0) \ { \ svga->vram[(addr) & mach64->vram_mask] = dest_dat; \ @@ -1216,10 +1220,17 @@ void mach64_start_line(mach64_t *mach64) } \ else \ { \ - if (dest_dat & 1) \ - svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (((addr) & 7)); \ - else \ - svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (((addr) & 7))); \ + if (dest_dat & 1) { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (7 - ((addr) & 7)); \ + } else { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (7 - ((addr) & 7)));\ + } \ svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \ } @@ -1247,7 +1258,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; int src_x; int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff; - + if (mach64->src_cntl & SRC_LINEAR_EN) src_x = mach64->accel.src_x; else @@ -1295,24 +1306,27 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mix = 1; break; case MONO_SRC_BLITSRC: - if (mach64->src_cntl & SRC_LINEAR_EN) { - READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); - } else { - READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); - } + if (mach64->src_cntl & SRC_LINEAR_EN) + { + READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); + } + else + { + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); + } break; } if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right && dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom) - { + { switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) { case SRC_HOST: src_dat = host_dat; break; case SRC_BLITSRC: - READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); break; case SRC_FG: src_dat = mach64->accel.dp_frgd_clr; @@ -1360,7 +1374,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16); mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16); } - + mach64->accel.src_x += mach64->accel.xinc; mach64->accel.dst_x += mach64->accel.xinc; if (!(mach64->src_cntl & SRC_LINEAR_EN)) @@ -1379,8 +1393,6 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) } } - - mach64->accel.x_count--; if (mach64->accel.x_count <= 0) @@ -1412,17 +1424,19 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mach64->accel.poly_draw = 0; mach64->accel.dst_height--; - + if (mach64->accel.dst_height <= 0) { /*Blit finished*/ +#ifdef MACH64_DEBUG + pclog("mach64 blit finished\n"); +#endif mach64->accel.busy = 0; if (mach64->dst_cntl & DST_X_TILE) mach64->dst_y_x = (mach64->dst_y_x & 0xfff) | ((mach64->dst_y_x + (mach64->accel.dst_width << 16)) & 0xfff0000); if (mach64->dst_cntl & DST_Y_TILE) mach64->dst_y_x = (mach64->dst_y_x & 0xfff0000) | ((mach64->dst_y_x + (mach64->dst_height_width & 0x1fff)) & 0xfff); - - return; + return; } if (mach64->host_cntl & HOST_BYTE_ALIGN) { @@ -2037,7 +2051,7 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) mach64_wait_fifo_idle(mach64); READ8(addr, mach64->dp_frgd_clr); break; - + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: mach64_wait_fifo_idle(mach64); READ8(addr, mach64->dp_pix_width); From 86a3941093a6394b83c82cf6e5fa4d7fb44f1024 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 16 Mar 2018 15:46:41 +0100 Subject: [PATCH 22/23] The DirectDraw renderer now also saves screenshots as PNG (using libpng). --- src/win/Makefile.mingw | 11 +- src/win/win.c | 13 +- src/win/win_ddraw.cpp | 157 +++++++++---- src/win/win_png.c | 508 ----------------------------------------- src/win/win_png.h | 66 ------ 5 files changed, 122 insertions(+), 633 deletions(-) delete mode 100644 src/win/win_png.c delete mode 100644 src/win/win_png.h diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index b5932d0e4..46c583632 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.111 2018/03/13 +# Version: @(#)Makefile.mingw 1.0.112 2018/03/16 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -292,7 +292,8 @@ ifneq ($(WX), n) LIBS += $(WX_LIBS) UIOBJ := wx_main.o wx_ui.o wx_stbar.o wx_render.o else - UIOBJ := win_ui.o win_ddraw.o win_d3d.o win_png.o \ + UIOBJ := win_ui.o \ + win_ddraw.o win_d3d.o \ win_dialog.o win_about.o win_status.o win_stbar.o \ win_settings.o win_devconf.o win_snd_gain.o \ win_new_floppy.o win_jsconf.o @@ -567,15 +568,15 @@ LIBS := -mwindows \ -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 \ -lcomctl32 -lwinmm ifeq ($(VNC), y) -LIBS += $(VNCLIB) -lws2_32 -lz +LIBS += $(VNCLIB) -lws2_32 endif ifeq ($(RDP), y) LIBS += $(RDPLIB) endif ifneq ($(WX), n) -LIBS += $(WX_LIBS) -lz -lm +LIBS += $(WX_LIBS) -lm endif -LIBS += -lkernel32 -lwsock32 -liphlpapi -lpsapi +LIBS += -lpng -lz -lkernel32 -lwsock32 -liphlpapi -lpsapi LIBS += -lpthread -static -lstdc++ -lgcc ifneq ($(X64), y) LIBS += -Wl,--large-address-aware diff --git a/src/win/win.c b/src/win/win.c index 0dde35c4b..d4ca6e66b 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,7 +8,7 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.45 2018/01/23 + * Version: @(#)win.c 1.0.46 2018/03/16 * * Authors: Sarah Walker, * Miran Grca, @@ -770,32 +770,27 @@ take_screenshot(void) wcscat(path, L"\\"); + wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); + wcscat(path, fn); + switch(vid_api) { #ifdef USE_WX case 0: case 1: - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); - wcscat(path, fn); wx_screenshot(path); break; #else case 0: /* ddraw */ - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.bmp", info); - wcscat(path, fn); ddraw_take_screenshot(path); break; case 1: /* d3d9 */ - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); - wcscat(path, fn); d3d_take_screenshot(path); break; #endif #ifdef USE_VNC case 2: /* vnc */ - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); - wcscat(path, fn); vnc_take_screenshot(path); break; #endif diff --git a/src/win/win_ddraw.cpp b/src/win/win_ddraw.cpp index 9fcd6e765..b211a6766 100644 --- a/src/win/win_ddraw.cpp +++ b/src/win/win_ddraw.cpp @@ -11,7 +11,7 @@ * NOTES: This code should be re-merged into a single init() with a * 'fullscreen' argument, indicating FS mode is requested. * - * Version: @(#)win_ddraw.cpp 1.0.5 2018/01/15 + * Version: @(#)win_ddraw.cpp 1.0.6 2018/03/16 * * Authors: Sarah Walker, * Miran Grca, @@ -27,13 +27,16 @@ #define BITMAP WINDOWS_BITMAP #include #undef BITMAP + +#define PNG_DEBUG 0 +#include + #include "../86box.h" #include "../device.h" #include "../video/video.h" #include "../plat.h" #include "../ui.h" #include "win_ddraw.h" -#include "win_png.h" #include "win.h" @@ -49,6 +52,9 @@ static HBITMAP hbitmap; static int ddraw_w, ddraw_h, xs, ys, ys2; +static png_structp png_ptr; +static png_infop info_ptr; + static void CopySurface(IDirectDrawSurface4 *pDDSurface) @@ -71,6 +77,24 @@ CopySurface(IDirectDrawSurface4 *pDDSurface) } +static void +bgra_to_rgb(png_bytep *b_rgb, uint8_t *bgra, int width, int height) +{ + int i, j; + uint8_t *r, *b; + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + r = &b_rgb[(height - 1) - i][j * 3]; + b = &bgra[((i * width) + j) * 4]; + r[0] = b[2]; + r[1] = b[1]; + r[2] = b[0]; + } + } +} + + static void DoubleLines(uint8_t *dst, uint8_t *src) { @@ -84,69 +108,112 @@ DoubleLines(uint8_t *dst, uint8_t *src) static void -SaveBitmap(wchar_t *szFilename, HBITMAP hBitmap) +SavePNG(wchar_t *szFilename, HBITMAP hBitmap) { - static WCHAR szMessage[512]; BITMAPFILEHEADER bmpFileHeader; BITMAPINFO bmpInfo; HDC hdc; - FILE *fp = NULL; LPVOID pBuf = NULL; LPVOID pBuf2 = NULL; + png_bytep *b_rgb = NULL; + int i; - do { - hdc = GetDC(NULL); + /* create file */ + FILE *fp = plat_fopen(szFilename, (wchar_t *) L"wb"); + if (!fp) { + pclog("[SavePNG] File %ls could not be opened for writing", szFilename); + return; + } - ZeroMemory(&bmpInfo, sizeof(BITMAPINFO)); - bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + /* initialize stuff */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS); + if (!png_ptr) { + pclog("[SavePNG] png_create_write_struct failed"); + fclose(fp); + return; + } - if (bmpInfo.bmiHeader.biSizeImage <= 0) - bmpInfo.bmiHeader.biSizeImage = - bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + pclog("[SavePNG] png_create_info_struct failed"); + fclose(fp); + return; + } - if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { -// pclog("ERROR: Unable to Allocate Bitmap Memory"); - break; + png_init_io(png_ptr, fp); + + hdc = GetDC(NULL); + + ZeroMemory(&bmpInfo, sizeof(BITMAPINFO)); + bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + + GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS); + + if (bmpInfo.bmiHeader.biSizeImage <= 0) + bmpInfo.bmiHeader.biSizeImage = + bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; + + if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { + pclog("[SavePNG] Unable to Allocate Bitmap Memory"); + fclose(fp); + return; + } + + if (ys2 <= 250) { + bmpInfo.bmiHeader.biSizeImage <<= 1; + + if ((pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { + pclog("[SavePNG] Unable to Allocate Secondary Bitmap Memory"); + free(pBuf); + fclose(fp); + return; } - if (ys2 <= 250) - pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage * 2); + bmpInfo.bmiHeader.biHeight <<= 1; + } - bmpInfo.bmiHeader.biCompression = BI_RGB; + pclog("save png w=%i h=%i\n", bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); - GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS); + bmpInfo.bmiHeader.biCompression = BI_RGB; - if ((fp = _wfopen(szFilename, L"wb")) == NULL) { - _swprintf(szMessage, - plat_get_string(IDS_2088), szFilename); - ui_msgbox(MBX_ERROR, szMessage); - break; - } + GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS); - bmpFileHeader.bfReserved1 = 0; - bmpFileHeader.bfReserved2 = 0; - if (pBuf2) { - bmpInfo.bmiHeader.biSizeImage <<= 1; - bmpInfo.bmiHeader.biHeight <<= 1; - } - bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage; - bmpFileHeader.bfType=0x4D42; - bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); + png_set_IHDR(png_ptr, info_ptr, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - (void)fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp); - (void)fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp); - if (pBuf2) { - DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf); - (void)fwrite(pBuf2,bmpInfo.bmiHeader.biSizeImage,1,fp); - } else { - (void)fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp); - } - } while(false); + if ((b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * bmpInfo.bmiHeader.biHeight)) == NULL) { + pclog("[SavePNG] Unable to Allocate RGB Bitmap Memory"); + free(pBuf2); + free(pBuf); + fclose(fp); + return; + } + for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) + b_rgb[i] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); + + if (pBuf2) { + DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf); + bgra_to_rgb(b_rgb, (uint8_t *) pBuf2, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); + } else + bgra_to_rgb(b_rgb, (uint8_t *) pBuf, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); + + png_write_info(png_ptr, info_ptr); + + png_write_image(png_ptr, b_rgb); + + png_write_end(png_ptr, NULL); + + /* cleanup heap allocation */ if (hdc) ReleaseDC(NULL,hdc); + for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) + if (b_rgb[i]) free(b_rgb[i]); + + if (b_rgb) free(b_rgb); + if (pBuf2) free(pBuf2); if (pBuf) free(pBuf); @@ -425,7 +492,7 @@ ddraw_take_screenshot(wchar_t *fn) CopySurface(lpdds_back2); - SaveBitmap(fn, hbitmap); + SavePNG(fn, hbitmap); } diff --git a/src/win/win_png.c b/src/win/win_png.c deleted file mode 100644 index 61fb1e57f..000000000 --- a/src/win/win_png.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * 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. - * - * Simple PNG image file format handler. - * - * Adapted for use with 86Box. Writing of (very basic) PNG - * image files, mostly intended to be used for creating - * screenshots. We only support sRGB format (3-byte pixel - * data) with a color depth of 8 bits per sample- so, 24bpp. - * - * NOTES: This is a stripped-down version of my full library for PNG - * image file format support. All the 'reading' code has been - * removed, and some other stuff we don't need in 86Box. - * - * TODO: Compression is currently not supported, until I figure out - * how ZLIB works so I can interface with it here. - * - * Version: @(#)win_png.c 1.0.1 2017/11/11 - * - * Author: Fred N. van Kempen, - * - * Copyright 2017 Fred N. van Kempen. - */ -#include -#include -#include -#include -#include "../86Box.h" -#include "../plat.h" -#include "win_png.h" - - -#ifdef CRC_DYNAMIC -static uint32_t crc_table[256]; -static int crc_tblok = 0; - - -/* Pre-calculate the CRC table. */ -static void -crc_create(void) -{ - uint32_t crc; - int i, k; - - for (i=0; i<256; i++) { - crc = (uint32_t)i; - for (k=0; k<8; k++) { - if (crc & 1) - crc = 0xedb88320UL ^ (crc >> 1); - else - crc >>= 1; - } - crc_table[i] = crc; - } - - crc_tblok = 1; -} - - -#else -static uint32_t crc_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; -#endif - - -/* Standard Network CRC32. */ -static uint32_t -crc_upd(uint32_t crc, uint8_t *bufp, int buflen) -{ - int i; - -#ifdef CRC_DYNAMIC - if (! crc_tblok) - crc_create(); -#endif - - for (i=0; i> 8); - - return(crc); -} - - -static uint32_t -crc_init(void) -{ - return(0xffffffffUL); -} - - -static uint32_t -crc_finish(uint32_t crc) -{ - return(crc ^ 0xffffffffUL); -} - - -/* Perform CRC over the compressed data. */ -static uint32_t -png_dcrc(uint32_t state, const uint8_t *bufp, uint32_t buflen) -{ - uint16_t s1, s2; - uint32_t i; - - s1 = (uint16_t)(state & 0xffff); - s2 = (uint16_t)(state >> 16); - - for (i=0; ifp) != sizeof(buff)) { - pclog("PNG(%ls): could not write trailer chunk!\n", png->name); - return(-1); - } - - /* All is good! */ - return(0); -} - - -/* Write an IDAT chunk header to the file. */ -static uint32_t -png_wridat(png_t *png, uint32_t pixels) -{ - uint8_t buff[10]; - uint32_t cnt; - int i, fluff; - - /* - * We must know the size of the chunk we are about to write, - * and that is not straightforward. If compression is enabled, - * we won't know until we're done with the chunk, so we would - * have to just write a dummy, and then go back afterwards and - * fix up the chunk size. - * - * Without compression, we could do the same, or we can do some - * calculations on how much data we expect to generate, and use - * that. For now, we'll go with the latter option. - */ - cnt = png->lwidth; /* bytes per scanline */ - cnt += 1; /* filter type per line */ - cnt *= (pixels/png->width); /* number of full lines */ - cnt += (pixels%png->width); /* number of pixels */ - - /* - * We now have the total number of pixel bytes to write. - * - * All that is left is adding the expected overhead (since we - * are dealing with fixed-size blocks and their headers) and - * that should give us the grand total.. - */ - i = (cnt / DEFL_MAX_BLKSZ); /* number of full blocks */ - if ((cnt % DEFL_MAX_BLKSZ) != 0) i++; /* incomplete block */ - cnt += (i * 5); /* block header is 5 bytes */ - - /* - * We are not using compression, so we must account for - * the extra data we insert to fake that. Below you will - * see the two DEFLATE bytes (this makes it look like a - * real deflate stream.) Upon closing, we also add the - * four compressed-data CRC bytes, so, a total of 6. - */ - fluff = 6; - - i = 0; - png_putlong(&buff[i], cnt+fluff, &i); /* IDAT chunk */ - memcpy(&buff[i], "IDAT", 4); i += 4; - buff[i++] = 0x08; /* deflate data: zlib */ - buff[i++] = 0x1d; /* zlib method number */ - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): unable to write IDAT header!\n", png->name); - png_close(png); - return(-1); - } - - /* Initialize IDAT CRC. */ - png->crc = crc_upd(png->crc, &buff[4], i-4); - - /* Initialize for writing data. */ - png->bufcnt = 0; /* no data in buffer */ - - return(cnt); -} - - -/* - * API: Write (more) data to the PNG file. - * - * To keep things semi-simple, we generate a single IDAT - * chunk for each write. So, if the application calls us - * with the entire image, we have one IDAT. If it calls - * us multiple times (for example, once per scanline), we - * get one IDAT per scanline. - */ -int -png_write(png_t *png, uint8_t *bitmap, uint32_t pixels) -{ - uint8_t buff[10]; - uint32_t cnt, n; - uint16_t s; - int i; - - /* Do they want to close up? */ - if (bitmap == NULL && pixels == 0) { - i = png_wriend(png); - return(i); - } - - if (png->line >= png->height) { - pclog("PNG(%ls): cannot write %u pixels!\n", png->name, pixels); - png_close(png); - return(-1); - } - - /* Start a new IDAT chunk. */ - cnt = png_wridat(png, pixels); - - /* Loop, writing all pixels to the file. */ - while (cnt > 0) { - if (png->bufcnt == 0) { - /* - * Initialize a new block header. - * - * Bit0: LastBlock - * Bits[2:1]: compression type (00=stored) - * Len: block size (MSB) - * Nlen: block size, negated (MSB) - */ - s = (cnt < DEFL_MAX_BLKSZ) ? cnt : DEFL_MAX_BLKSZ; - i = 0; - buff[i++] = (cnt <= DEFL_MAX_BLKSZ) ? 1:0; - buff[i++] = ((s >> 8) & 0xff); - buff[i++] = (s & 0xff); - buff[i++] = ((s >> 8) ^ 0xff); - buff[i++] = (s ^ 0xff); - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): block header write failed!\n", - png->name); - png_close(png); - return(-1); - } - png->crc = crc_upd(png->crc, buff, i); - cnt -= i; - } - - if (png->col == 0) { - /* Beginning of line, write filter method. */ - buff[0] = 0x00; - if (fwrite(buff, 1, 1, png->fp) != 1) { - pclog("PNG(%ls): cannot write filter?!\n", png->name); - png_close(png); - return(-1); - } - png->crc = crc_upd(png->crc, buff, 1); - png->dcrc = png_dcrc(png->dcrc, buff, 1); - png->bufcnt++; - cnt--; - } - - /* See how many pixels we can write for this scanline. */ - n = cnt; - if ((png->lwidth - png->col) < n) - n = (png->lwidth - png->col); - if ((DEFL_MAX_BLKSZ - png->bufcnt) < n) - n = (DEFL_MAX_BLKSZ - png->bufcnt); - - /* Write the pixel data for this block. */ - if (fwrite(bitmap, 1, n, png->fp) != n) { - pclog("PNG(%ls): cannot write pixeldata?!\n", png->name); - png_close(png); - return(-1); - } - - /* Update the CRCs for these pixels. */ - png->crc = crc_upd(png->crc, bitmap, n); - png->dcrc = png_dcrc(png->dcrc, bitmap, n); - - /* Update stats. */ - bitmap += n; - png->bufcnt += n; - if (png->bufcnt == DEFL_MAX_BLKSZ) - png->bufcnt = 0; - cnt -= n; - - png->col += n; - if (png->col == png->lwidth) { - png->col = 0; - if (++png->line == png->height) { - if (cnt > 0) { - pclog("PNG(%ls): done, more data?!\n", - png->name); - png_close(png); - return(-1); - } - } - } - } - - /* Write the CRCs. */ - i = 0; - png_putlong(buff, png->dcrc, &i); - png->crc = crc_finish(crc_upd(png->crc, buff, i)); - png_putlong(&buff[i], png->crc, &i); - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): cannot write IDAT trailer?!\n", png->name); - png_close(png); - return(-1); - } - - return(0); -} - - -/* Write an unsigned long 32bit value in MSB. */ -void -png_putlong(uint8_t *ptr, uint32_t val, int *off) -{ - *ptr++ = (val >> 24) & 0xff; - *ptr++ = (val >> 16) & 0xff; - *ptr++ = (val >> 8) & 0xff; - *ptr = val & 0xff; - - if (off != NULL) - *off += sizeof(uint32_t); -} - - -/* API: Close the current PNG file. */ -void -png_close(png_t *png) -{ - if (png->fp != NULL) { - fflush(png->fp); - (void)fclose(png->fp); - - free(png); - } -} - - -/* API: Create a new PNG file. */ -png_t * -png_create(wchar_t *fn, int width, int height, int bpp) -{ - uint8_t buff[33]; - uint32_t crc; - png_t *png; - int i; - - /* Make sure we can do this. */ - if ((bpp != 24) || - (width<=0 || width >= 65536) || - (height<=0 || height >= 65536)) { - pclog("PNG(%ls): invalid image parameters!\n", fn); - return(NULL); - } - - /* Allocate the control block. */ - png = (png_t *)malloc(sizeof(png_t)); - if (png == NULL) { - pclog("PNG(%ls): out of memory!\n", fn); - return(NULL); - } - memset(png, 0x00, sizeof(png_t)); - png->name = fn; - png->width = width; /* width, in pixels */ - png->height = height; /* height, in pixels */ - png->bpp = bpp; /* total bits per pixel */ - png->ctype = PNG_COLOR_TYPE; /* 02 - sRBG */ - png->cdepth = (bpp/3); /* bits per color sample */ - png->pwidth = (bpp/8); /* bytes per pixel */ - png->lwidth = (png->pwidth*width); /* line width in bytes */ - png->crc = crc_init(); /* initialize data CRC */ - png->dcrc = 1; /* compressed-data CRC */ - - /* Create the data file. */ - if ((png->fp = plat_fopen(fn, L"wb")) == NULL) { - pclog("PNG(%ls): unable to create file!\n", fn); - png_close(png); - return(NULL); - } - - /* Write out the basic header chunks. */ - i = 0; - buff[i++] = 0x89; /* standard PNG header */ - memcpy(&buff[i], "PNG", 3); i += 3; - buff[i++] = 0x0d; buff[i++] = 0x0a; - buff[i++] = 0x1a; buff[i++] = 0x0a; - - png_putlong(&buff[i], 13, &i); /* IHDR chunk */ - memcpy(&buff[i], "IHDR", 4); i += 4; - png_putlong(&buff[i], png->width, &i); /* width */ - png_putlong(&buff[i], png->height, &i); /* height */ - buff[i++] = png->cdepth; /* color depth (per color) */ - buff[i++] = png->ctype; /* color type (2=RGB) */ - buff[i++] = PNG_COMPRESSION_TYPE; /* compression (0=deflate) */ - buff[i++] = PNG_FILTER_TYPE; /* filter (0=adaptive) */ - buff[i++] = PNG_INTERLACE_MODE; /* interlace (0=none) */ - crc = crc_finish(crc_upd(crc_init(), &buff[12], 17)); - png_putlong(&buff[i], crc, &i); - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): unable to write PNG header!\n", fn); - png_close(png); - return(NULL); - } - - i = 4; - memcpy(&buff[i], "tEXt", 4); i += 4; - memcpy(&buff[i], "Software", 8); i+= 8; - buff[i++] = 0x00; - memcpy(&buff[i], "86Box PNGlib", 12); i+= 12; - png_putlong(buff, i-8, NULL); - crc = crc_finish(crc_upd(crc_init(), &buff[4], i-4)); - png_putlong(&buff[i], crc, &i); - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): unable to write chunk header!\n", fn); - png_close(png); - return(NULL); - } - - return(png); -} diff --git a/src/win/win_png.h b/src/win/win_png.h deleted file mode 100644 index 0cafdf5c8..000000000 --- a/src/win/win_png.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - * - * Definitions for the Simple PNG image file format handler. - * - * Version: @(#)win_png.h 1.0.1 2017/11/11 - * - * Author: Fred N. van Kempen, - * - * Copyright 2017 Fred N. van Kempen. - */ -#ifndef WIN_PNG_H -# define WIN_PNG_H - - -/* PNG defintions, as per the specification. */ -#define PNG_COLOR_TYPE 0x02 /* 3-sample sRGB */ -#define PNG_COMPRESSION_TYPE 0x00 /* deflate compression */ -#define PNG_FILTER_TYPE 0x00 /* no filtering */ -#define PNG_INTERLACE_MODE 0x00 /* no interlacing */ - -/* DEFLATE definition, as per RFC1950/1 specification. */ -#define DEFL_MAX_BLKSZ 65535 /* DEFLATE max block size */ - - -typedef struct { - wchar_t *name; /* name of datafile */ - FILE *fp; - - uint16_t width, /* configured with in pixels */ - height; /* configured with in pixels */ - uint8_t bpp, /* configured bits per pixel */ - ctype; /* configured color type */ - - uint16_t col, /* current column */ - line, /* current scanline */ - lwidth; /* line width in bytes */ - uint8_t cdepth, /* color depth in bits */ - pwidth; /* bytes per pixel */ - uint32_t crc; /* idat chunk crc */ - uint32_t dcrc; /* deflate data crc */ - - uint32_t bufcnt; /* #bytes in block */ -} png_t; - - -#ifdef __cplusplus -extern "C" { -#endif - -extern void png_putlong(uint8_t *ptr, uint32_t val, int *off); -extern void png_close(png_t *png); -extern png_t *png_create(wchar_t *fn, int width, int height, int bpp); -extern int png_write(png_t *png, uint8_t *bitmap, uint32_t pixels); - -#ifdef __cplusplus -} -#endif - - -#endif /*WIN_PNG_H*/ From a6ed6cde1ed94030ad3e181cd6e040c09815a91c Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 16 Mar 2018 19:03:20 +0100 Subject: [PATCH 23/23] The IDE buffer is now correctly allocated at a size of 65536 words rather than bytes, fixes crashes with some machines. --- src/disk/hdc_ide.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index b2743528b..d07532abd 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.34 2018/03/15 + * Version: @(#)hdc_ide.c 1.0.35 2018/03/16 * * Authors: Sarah Walker, * Miran Grca, @@ -885,7 +885,7 @@ void ide_reset(void) if (ide_drives[d].type != IDE_NONE) { ide_drives[d].buffer = NULL; /* Important, makes sure malloc does not reuse an existing pointer from elsewhere. */ - ide_drives[d].buffer = (uint16_t *) malloc(65536); + ide_drives[d].buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); } ide_set_signature(&ide_drives[d]);