diff --git a/src/chipset/chipset.h b/src/chipset/chipset.h index f61cdcd3e..b78f177c5 100644 --- a/src/chipset/chipset.h +++ b/src/chipset/chipset.h @@ -64,6 +64,9 @@ extern const device_t sis_85c50x_device; /* VIA */ extern const device_t via_mvp3_device; +/* VLSI */ +extern const device_t vlsi_scamp_device; + /* WD */ extern const device_t wd76c10_device; diff --git a/src/chipset/scamp.c b/src/chipset/scamp.c new file mode 100644 index 000000000..093b3863a --- /dev/null +++ b/src/chipset/scamp.c @@ -0,0 +1,756 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Emulation of VLSI 82C311 ("SCAMP") chipset. + * + * Note: The datasheet mentions that the chipset supports up to 8MB + * of DRAM. This is intepreted as 'being able to refresh up to + * 8MB of DRAM chips', because it works fine with bus-based + * memory expansion. + * + * Version: @(#)scamp.c 1.0.0 2020/01/21 + * + * Authors: Sarah Walker, + * + * Copyright 2020 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../timer.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../port_92.h" +#include "chipset.h" + +typedef struct { + int cfg_index; + uint8_t cfg_regs[256]; + int cfg_enable; + + int ram_config; + + mem_mapping_t ram_mapping[2]; + uint32_t ram_virt_base[2], ram_phys_base[2]; + uint32_t ram_mask[2]; + int row_virt_shift[2], row_phys_shift[2]; + int ram_interleaved[2]; + int ibank_shift[2]; +} scamp_t; + +#define CFG_ID 0x00 +#define CFG_SLTPTR 0x02 +#define CFG_RAMMAP 0x03 +#define CFG_EMSEN1 0x0b +#define CFG_EMSEN2 0x0c +#define CFG_ABAXS 0x0e +#define CFG_CAXS 0x0f +#define CFG_DAXS 0x10 +#define CFG_FEAXS 0x11 + +#define ID_VL82C311 0xd6 + +#define RAMMAP_REMP386 (1 << 4) + +/*Commodore SL386SX requires proper memory slot decoding to detect memory size. + Therefore we emulate the SCAMP memory address decoding, and therefore are + limited to the DRAM combinations supported by the actual chip*/ +enum +{ + BANK_NONE, + BANK_256K, + BANK_256K_INTERLEAVED, + BANK_1M, + BANK_1M_INTERLEAVED, + BANK_4M, + BANK_4M_INTERLEAVED +}; + +static const struct +{ + int size_kb; + int rammap; + int bank[2]; +} ram_configs[] = +{ + {512, 0x0, {BANK_256K, BANK_NONE}}, + {1024, 0x1, {BANK_256K_INTERLEAVED, BANK_NONE}}, + {1536, 0x2, {BANK_256K_INTERLEAVED, BANK_256K}}, + {2048, 0x3, {BANK_256K_INTERLEAVED, BANK_256K_INTERLEAVED}}, + {3072, 0xc, {BANK_256K_INTERLEAVED, BANK_1M}}, + {4096, 0x5, {BANK_1M_INTERLEAVED, BANK_NONE}}, + {5120, 0xd, {BANK_256K_INTERLEAVED, BANK_1M_INTERLEAVED}}, + {6144, 0x6, {BANK_1M_INTERLEAVED, BANK_1M}}, + {8192, 0x7, {BANK_1M_INTERLEAVED, BANK_1M_INTERLEAVED}}, + {12288, 0xe, {BANK_1M_INTERLEAVED, BANK_4M}}, + {16384, 0x9, {BANK_4M_INTERLEAVED, BANK_NONE}}, +}; + +static const struct +{ + int bank[2]; + int remapped; +} rammap[16] = +{ + {{BANK_256K, BANK_NONE}, 0}, + {{BANK_256K_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_256K_INTERLEAVED, BANK_256K}, 0}, + {{BANK_256K_INTERLEAVED, BANK_256K_INTERLEAVED}, 0}, + + {{BANK_1M, BANK_NONE}, 0}, + {{BANK_1M_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_1M_INTERLEAVED, BANK_1M}, 0}, + {{BANK_1M_INTERLEAVED, BANK_1M_INTERLEAVED}, 0}, + + {{BANK_4M, BANK_NONE}, 0}, + {{BANK_4M_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_NONE, BANK_4M}, 1}, /*Bank 2 remapped to 0*/ + {{BANK_NONE, BANK_4M_INTERLEAVED}, 1}, /*Banks 2/3 remapped to 0/1*/ + + {{BANK_256K_INTERLEAVED, BANK_1M}, 0}, + {{BANK_256K_INTERLEAVED, BANK_1M_INTERLEAVED}, 0}, + {{BANK_1M_INTERLEAVED, BANK_4M}, 0}, + {{BANK_1M_INTERLEAVED, BANK_4M_INTERLEAVED}, 0}, /*Undocumented - probably wrong!*/ +}; + +/*The column bits masked when using 256kbit DRAMs in 4Mbit mode aren't contiguous, + so we use separate routines for that special case*/ +static uint8_t +ram_mirrored_256k_in_4mi_read(uint32_t addr, void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + int bank = (int)priv; + int row, column, byte; + + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + if (!dev->ram_interleaved[bank]) { + if (addr & 0x400) + return 0xff; + + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & dev->ram_mask[bank]; + row = ((addr & 0xff000) >> 13) | (((addr & 0x200000) >> 22) << 9); + + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + } else { + column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); + row = ((addr & 0x1fe000) >> 13) | (((addr & 0x400000) >> 22) << 9); + + addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); + } + + return ram[addr + dev->ram_phys_base[bank]]; +} +static void +ram_mirrored_256k_in_4mi_write(uint32_t addr, uint8_t val, void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + int bank = (int)priv; + int row, column, byte; + + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + if (!dev->ram_interleaved[bank]) { + if (addr & 0x400) + return; + + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & dev->ram_mask[bank]; + row = ((addr & 0xff000) >> 13) | (((addr & 0x200000) >> 22) << 9); + + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + } else { + column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); + row = ((addr & 0x1fe000) >> 13) | (((addr & 0x400000) >> 22) << 9); + + addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); + } + + ram[addr + dev->ram_phys_base[bank]] = val; +} + +/*Read/write handlers for interleaved memory banks. We must keep CPU and ram array + mapping linear, otherwise we won't be able to execute code from interleaved banks*/ +static uint8_t +ram_mirrored_interleaved_read(uint32_t addr, void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + int bank = (int)priv; + int row, column, byte; + + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + if (!dev->ram_interleaved[bank]) { + if (addr & 0x400) + return 0xff; + + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & dev->ram_mask[bank]; + row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; + + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + } else { + column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); + row = (addr >> (dev->row_virt_shift[bank]+1)) & dev->ram_mask[bank]; + + addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); + } + + return ram[addr + dev->ram_phys_base[bank]]; +} +static void +ram_mirrored_interleaved_write(uint32_t addr, uint8_t val, void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + int bank = (int)priv; + int row, column, byte; + + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + if (!dev->ram_interleaved[bank]) { + if (addr & 0x400) + return; + + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & dev->ram_mask[bank]; + row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; + + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + } + else { + column = (addr >> 1) & ((dev->ram_mask[bank] << 1) | 1); + row = (addr >> (dev->row_virt_shift[bank]+1)) & dev->ram_mask[bank]; + + addr = byte | (column << 1) | (row << (dev->row_phys_shift[bank]+1)); + } + + ram[addr + dev->ram_phys_base[bank]] = val; +} + +static uint8_t +ram_mirrored_read(uint32_t addr, void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + int bank = (int)priv; + int row, column, byte; + + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + column = (addr >> 1) & dev->ram_mask[bank]; + row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + + return ram[addr + dev->ram_phys_base[bank]]; +} +static void +ram_mirrored_write(uint32_t addr, uint8_t val, void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + int bank = (int)priv; + int row, column, byte; + + addr -= dev->ram_virt_base[bank]; + byte = addr & 1; + column = (addr >> 1) & dev->ram_mask[bank]; + row = (addr >> dev->row_virt_shift[bank]) & dev->ram_mask[bank]; + addr = byte | (column << 1) | (row << dev->row_phys_shift[bank]); + + ram[addr + dev->ram_phys_base[bank]] = val; +} + +static void +recalc_mappings(void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + int c; + uint32_t virt_base = 0; + uint8_t cur_rammap = dev->cfg_regs[CFG_RAMMAP] & 0xf; + int bank_nr = 0; + + for (c = 0; c < 2; c++) + mem_mapping_disable(&dev->ram_mapping[c]); + + /*Once the BIOS programs the correct DRAM configuration, switch to regular + linear memory mapping*/ + if (cur_rammap == ram_configs[dev->ram_config].rammap) { + mem_mapping_set_handler(&ram_low_mapping, + mem_read_ram, mem_read_ramw, mem_read_raml, + mem_write_ram, mem_write_ramw, mem_write_raml); + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_enable(&ram_high_mapping); + return; + } else { + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + mem_mapping_disable(&ram_low_mapping); + } + + if (rammap[cur_rammap].bank[0] == BANK_NONE) + bank_nr = 1; + +/* pclog("Bank remap, cur_rammap=%x\n", cur_rammap); */ + + for (; bank_nr < 2; bank_nr++) { + uint32_t old_virt_base = virt_base; + int phys_bank = ram_configs[dev->ram_config].bank[bank_nr]; + +/* pclog(" Bank %i: phys_bank=%i rammap_bank=%i virt_base=%08x phys_base=%08x\n", bank_nr, phys_bank, rammap[cur_rammap].bank[bank_nr], virt_base, dev->ram_phys_base[bank_nr]); */ + dev->ram_virt_base[bank_nr] = virt_base; + + if (virt_base == 0) { + switch (rammap[cur_rammap].bank[bank_nr]) { + case BANK_NONE: + fatal("Bank 0 is empty!\n"); + break; + + case BANK_256K: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0x80000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + } + virt_base += 512*1024; + dev->row_virt_shift[bank_nr] = 10; + break; + + case BANK_256K_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + } + virt_base += 512*1024*2; + dev->row_virt_shift[bank_nr] = 10; + break; + + case BANK_1M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x100000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + } + virt_base += 2048*1024; + dev->row_virt_shift[bank_nr] = 11; + break; + + case BANK_1M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x300000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + } + virt_base += 2048*1024*2; + dev->row_virt_shift[bank_nr] = 11; + break; + + case BANK_4M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0x700000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + } + virt_base += 8192*1024; + dev->row_virt_shift[bank_nr] = 12; + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], 0x100000, 0xf00000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr] + 0x100000]); + } + virt_base += 8192*1024*2; + dev->row_virt_shift[bank_nr] = 12; + break; + } + } else { + switch (rammap[cur_rammap].bank[bank_nr]) { + case BANK_NONE: + break; + + case BANK_256K: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x80000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + } + virt_base += 512*1024; + dev->row_virt_shift[bank_nr] = 10; + break; + + case BANK_256K_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x100000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + } + virt_base += 512*1024*2; + dev->row_virt_shift[bank_nr] = 10; + break; + + case BANK_1M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x200000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + } + virt_base += 2048*1024; + dev->row_virt_shift[bank_nr] = 11; + break; + + case BANK_1M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x400000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + } + virt_base += 2048*1024*2; + dev->row_virt_shift[bank_nr] = 11; + break; + + case BANK_4M: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x800000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + } + virt_base += 8192*1024; + dev->row_virt_shift[bank_nr] = 12; + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank != BANK_NONE) { + mem_mapping_set_addr(&dev->ram_mapping[bank_nr], virt_base, 0x1000000); + mem_mapping_set_exec(&dev->ram_mapping[bank_nr], &ram[dev->ram_phys_base[bank_nr]]); + } + virt_base += 8192*1024*2; + dev->row_virt_shift[bank_nr] = 12; + break; + } + } + switch (rammap[cur_rammap].bank[bank_nr]) { + case BANK_256K: case BANK_1M: case BANK_4M: + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + /*pclog(" not interleaved\n");*/ + break; + + case BANK_256K_INTERLEAVED: case BANK_1M_INTERLEAVED: + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + /*pclog(" interleaved\n");*/ + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank == BANK_256K || phys_bank == BANK_256K_INTERLEAVED) { + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + ram_mirrored_256k_in_4mi_read, NULL, NULL, + ram_mirrored_256k_in_4mi_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_256k_in_4mi_read, NULL, NULL, + ram_mirrored_256k_in_4mi_write, NULL, NULL); + /*pclog(" 256k in 4mi\n");*/ + } else { + mem_mapping_set_handler(&dev->ram_mapping[bank_nr], + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + /*pclog(" interleaved\n");*/ + } + break; + } + } +} + +#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0])) + + +static void +shadow_control(uint32_t addr, uint32_t size, int state) +{ +/* pclog("shadow_control: addr=%08x size=%04x state=%i\n", addr, size, state); */ + switch (state) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_EXTANY | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTANY); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +static void +scamp_write(uint16_t addr, uint8_t val, void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + +/* pclog("scamp_write: addr=%04x val=%02x\n", addr, val); */ + switch (addr) { + case 0xec: + if (dev->cfg_enable) + dev->cfg_index = val; + break; + + case 0xed: + if (dev->cfg_enable) { + if (dev->cfg_index >= 0x02 && dev->cfg_index <= 0x16) { + dev->cfg_regs[dev->cfg_index] = val; +/* pclog("SCAMP CFG[%02x]=%02x\n", dev->cfg_index, val); */ + switch (dev->cfg_index) { + case CFG_SLTPTR: + break; + + case CFG_RAMMAP: + recalc_mappings(dev); + mem_mapping_disable(&ram_remapped_mapping); + if (dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) { + /*Enabling remapping will disable all shadowing*/ + mem_remap_top(384); + shadow_control(0xa0000, 0x60000, 0); + } else { + shadow_control(0xa0000, 0x8000, dev->cfg_regs[CFG_ABAXS] & 3); + shadow_control(0xa8000, 0x8000, (dev->cfg_regs[CFG_ABAXS] >> 2) & 3); + shadow_control(0xb0000, 0x8000, (dev->cfg_regs[CFG_ABAXS] >> 4) & 3); + shadow_control(0xb8000, 0x8000, (dev->cfg_regs[CFG_ABAXS] >> 6) & 3); + + shadow_control(0xc0000, 0x4000, dev->cfg_regs[CFG_CAXS] & 3); + shadow_control(0xc4000, 0x4000, (dev->cfg_regs[CFG_CAXS] >> 2) & 3); + shadow_control(0xc8000, 0x4000, (dev->cfg_regs[CFG_CAXS] >> 4) & 3); + shadow_control(0xcc000, 0x4000, (dev->cfg_regs[CFG_CAXS] >> 6) & 3); + + shadow_control(0xd0000, 0x4000, dev->cfg_regs[CFG_DAXS] & 3); + shadow_control(0xd4000, 0x4000, (dev->cfg_regs[CFG_DAXS] >> 2) & 3); + shadow_control(0xd8000, 0x4000, (dev->cfg_regs[CFG_DAXS] >> 4) & 3); + shadow_control(0xdc000, 0x4000, (dev->cfg_regs[CFG_DAXS] >> 6) & 3); + + shadow_control(0xe0000, 0x8000, dev->cfg_regs[CFG_FEAXS] & 3); + shadow_control(0xe8000, 0x8000, (dev->cfg_regs[CFG_FEAXS] >> 2) & 3); + shadow_control(0xf0000, 0x8000, (dev->cfg_regs[CFG_FEAXS] >> 4) & 3); + shadow_control(0xf8000, 0x8000, (dev->cfg_regs[CFG_FEAXS] >> 6) & 3); + } + break; + + case CFG_ABAXS: + if (!(dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) { + shadow_control(0xa0000, 0x8000, val & 3); + shadow_control(0xa8000, 0x8000, (val >> 2) & 3); + shadow_control(0xb0000, 0x8000, (val >> 4) & 3); + shadow_control(0xb8000, 0x8000, (val >> 6) & 3); + } + break; + + case CFG_CAXS: + if (!(dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) { + shadow_control(0xc0000, 0x4000, val & 3); + shadow_control(0xc4000, 0x4000, (val >> 2) & 3); + shadow_control(0xc8000, 0x4000, (val >> 4) & 3); + shadow_control(0xcc000, 0x4000, (val >> 6) & 3); + } + break; + + case CFG_DAXS: + if (!(dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) { + shadow_control(0xd0000, 0x4000, val & 3); + shadow_control(0xd4000, 0x4000, (val >> 2) & 3); + shadow_control(0xd8000, 0x4000, (val >> 4) & 3); + shadow_control(0xdc000, 0x4000, (val >> 6) & 3); + } + break; + + case CFG_FEAXS: + if (!(dev->cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) { + shadow_control(0xe0000, 0x8000, val & 3); + shadow_control(0xe8000, 0x8000, (val >> 2) & 3); + shadow_control(0xf0000, 0x8000, (val >> 4) & 3); + shadow_control(0xf8000, 0x8000, (val >> 6) & 3); + } + break; + } + } + } + break; + + case 0xee: + if (dev->cfg_enable && mem_a20_alt) + outb(0x92, inb(0x92) & ~2); + break; + } +} + + +static uint8_t +scamp_read(uint16_t addr, void *priv) +{ + uint8_t ret = 0xff; + + switch (addr) { + case 0xee: + if (!mem_a20_alt) + outb(0x92, inb(0x92) | 2); + break; + + case 0xef: + softresetx86(); + cpu_set_edx(); + break; + } + +/* pclog("scamp_read: addr=%04x ret=%02x\n", addr, ret); */ + return ret; +} + +static void +scamp_close(void *priv) +{ + scamp_t *dev = (scamp_t *) priv; + + free(dev); +} + + +static void * +scamp_init(const device_t *info) +{ + uint32_t addr; + int c; + scamp_t *dev = (scamp_t *)malloc(sizeof(scamp_t)); + memset(dev, 0, sizeof(scamp_t)); + + dev->cfg_regs[CFG_ID] = ID_VL82C311; + dev->cfg_enable = 1; + + io_sethandler(0x00e8, 0x0001, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + io_sethandler(0x00ea, 0x0006, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + io_sethandler(0x00f4, 0x0002, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + io_sethandler(0x00f9, 0x0001, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + io_sethandler(0x00fb, 0x0001, + scamp_read, NULL, NULL, scamp_write, NULL, NULL, dev); + + dev->ram_config = 0; + + /*Find best fit configuration for the requested memory size*/ + for (c = 0; c < NR_ELEMS(ram_configs); c++) { + if (mem_size < ram_configs[c].size_kb) + break; + + dev->ram_config = c; + } + + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + mem_mapping_disable(&ram_high_mapping); + + addr = 0; + for (c = 0; c < 2; c++) { + mem_mapping_add(&dev->ram_mapping[c], 0, 0, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL, + &ram[addr], MEM_MAPPING_INTERNAL, (void *)c); + mem_mapping_disable(&dev->ram_mapping[c]); + + dev->ram_phys_base[c] = addr; +/* pclog("Bank calc : %i = %08x\n", c ,addr);*/ + + switch (ram_configs[dev->ram_config].bank[c]) { + case BANK_NONE: + dev->ram_mask[c] = 0; + dev->ram_interleaved[c] = 0; + break; + + case BANK_256K: + addr += 512*1024; + dev->ram_mask[c] = 0x1ff; + dev->row_phys_shift[c] = 10; + dev->ram_interleaved[c] = 0; + break; + + case BANK_256K_INTERLEAVED: + addr += 512*1024*2; + dev->ram_mask[c] = 0x1ff; + dev->row_phys_shift[c] = 10; + dev->ibank_shift[c] = 19; + dev->ram_interleaved[c] = 1; + break; + + case BANK_1M: + addr += 2048*1024; + dev->ram_mask[c] = 0x3ff; + dev->row_phys_shift[c] = 11; + dev->ram_interleaved[c] = 0; + break; + + case BANK_1M_INTERLEAVED: + addr += 2048*1024*2; + dev->ram_mask[c] = 0x3ff; + dev->row_phys_shift[c] = 11; + dev->ibank_shift[c] = 21; + dev->ram_interleaved[c] = 1; + break; + + case BANK_4M: + addr += 8192*1024; + dev->ram_mask[c] = 0x7ff; + dev->row_phys_shift[c] = 12; + dev->ram_interleaved[c] = 0; + break; + + case BANK_4M_INTERLEAVED: + addr += 8192*1024*2; + dev->ram_mask[c] = 0x7ff; + dev->row_phys_shift[c] = 12; + dev->ibank_shift[c] = 23; + dev->ram_interleaved[c] = 1; + break; + } + } + + mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_EXTANY | MEM_WRITE_EXTANY); + + return dev; +} + + +const device_t vlsi_scamp_device = { + "VLSI SCAMP", + 0, + 0, + scamp_init, scamp_close, NULL, + NULL, NULL, NULL, + NULL +}; \ No newline at end of file diff --git a/src/machine/m_at_286_386sx.c b/src/machine/m_at_286_386sx.c index 52193d402..d977d37b3 100644 --- a/src/machine/m_at_286_386sx.c +++ b/src/machine/m_at_286_386sx.c @@ -8,7 +8,7 @@ * * Implementation of 286 and 386SX machines. * - * Version: @(#)m_at_286_386sx.c 1.0.2 2019/11/19 + * Version: @(#)m_at_286_386sx.c 1.0.3 2020/01/22 * * Authors: Sarah Walker, * Miran Grca, @@ -35,6 +35,7 @@ #include "../floppy/fdc.h" #include "../disk/hdc.h" #include "../video/video.h" +#include "../video/vid_cl54xx.h" #include "../video/vid_et4000.h" #include "../video/vid_oak_oti.h" #include "../video/vid_paradise.h" @@ -409,3 +410,33 @@ machine_at_wd76c10_init(const machine_t *model) return ret; } + +const device_t * +at_commodore_sl386sx_get_device(void) +{ + return &gd5402_onboard_device; +} + +int +machine_at_commodore_sl386sx_init(const machine_t *model) +{ + int ret; + + ret = bios_load_interleaved(L"roms/machines/cbm_sl386sx25/cbm-sl386sx-bios-lo-v1.04-390914-04.bin", + L"roms/machines/cbm_sl386sx25/cbm-sl386sx-bios-hi-v1.04-390915-04.bin", + 0x000f0000, 65536, 0); + + if (bios_only || !ret) + return ret; + + machine_at_common_ide_init(model); + + device_add(&keyboard_at_device); + device_add(&fdc_at_device); + device_add(&vlsi_scamp_device); + + if (gfxcard == VID_INTERNAL) + device_add(&gd5402_onboard_device); + + return ret; +} diff --git a/src/machine/machine.h b/src/machine/machine.h index 53353f7cc..72f6f199e 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.36 2020/01/20 + * Version: @(#)machine.h 1.0.37 2020/01/22 * * Authors: Sarah Walker, * Miran Grca, @@ -201,10 +201,12 @@ extern int machine_at_spc4216p_init(const machine_t *); extern int machine_at_kmxc02_init(const machine_t *); extern int machine_at_deskmaster286_init(const machine_t *); +extern int machine_at_commodore_sl386sx_init(const machine_t *); extern int machine_at_wd76c10_init(const machine_t *); #ifdef EMU_DEVICE_H -extern const device_t *at_ama932j_get_device(void); +extern const device_t *at_ama932j_get_device(void); +extern const device_t *at_commodore_sl386sx_get_device(void); #endif /* m_at_386dx_486.c */ diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index e0dd2570b..2af281f54 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.53 2020/01/20 + * Version: @(#)machine_table.c 1.0.54 2020/01/22 * * Authors: Sarah Walker, * Miran Grca, @@ -127,6 +127,7 @@ const machine_t machines[] = { { "[386SX ISA] AMI Unknown 386SX", "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, #endif { "[386SX ISA] Amstrad MegaPC", "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386SX ISA] Commodore SL386SX", "cbm_sl386sx25", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1024, 8192, 512, 127, machine_at_commodore_sl386sx_init, at_commodore_sl386sx_get_device }, { "[386SX ISA] DTK 386SX clone", "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_neat_init, NULL }, { "[386SX ISA] IBM PS/1 model 2121", "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, { "[386SX ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, diff --git a/src/machine/machine_table_new.c b/src/machine/machine_table_new.c index 30223d562..8787c911c 100644 --- a/src/machine/machine_table_new.c +++ b/src/machine/machine_table_new.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.53 2020/01/20 + * Version: @(#)machine_table.c 1.0.54 2020/01/22 * * Authors: Sarah Walker, * Miran Grca, @@ -112,6 +112,7 @@ const machine_t machines[] = { { "[386SX ISA] AMI Unknown 386SX", "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, #endif { "[386SX ISA] Amstrad MegaPC", "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386SX ISA] Commodore SL386SX", "cbm_sl386sx25", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1024, 8192, 512, 127, machine_at_commodore_sl386sx_init, at_commodore_sl386sx_get_device }, { "[386SX ISA] DTK 386SX clone", "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512, 8192, 128, 127, machine_at_neat_init, NULL }, { "[386SX ISA] IBM PS/1 model 2121", "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO | MACHINE_VIDEO_FIXED, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, { "[386SX ISA] IBM PS/1 m.2121+ISA", "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 1ba5b7a38..65e2d66f0 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,7 +9,7 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). * - * Version: @(#)vid_cl_54xx.c 1.0.32 2020/01/11 + * Version: @(#)vid_cl_54xx.c 1.0.32 2020/01/22 * * Authors: TheCollector1995, * Miran Grca, @@ -36,10 +36,13 @@ #include "vid_svga_render.h" #include "vid_cl54xx.h" -#if defined(DEV_BRANCH) && defined(USE_CL5422) +#define BIOS_GD5402_PATH L"roms/video/cirruslogic/avga2.rom" #define BIOS_GD5420_PATH L"roms/video/cirruslogic/5420.vbi" + +#if defined(DEV_BRANCH) && defined(USE_CL5422) #define BIOS_GD5422_PATH L"roms/video/cirruslogic/cl5422.bin" #endif + #define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" #define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.bin" #define BIOS_GD5428_PATH L"roms/video/cirruslogic/vlbusjapan.BIN" @@ -2906,21 +2909,25 @@ static void gd54xx->has_bios = 1; switch (id) { -#if defined(DEV_BRANCH) && defined(USE_CL5422) case CIRRUS_ID_CLGD5402: + romfn = BIOS_GD5402_PATH; + break; + case CIRRUS_ID_CLGD5420: romfn = BIOS_GD5420_PATH; break; + +#if defined(DEV_BRANCH) && defined(USE_CL5422) case CIRRUS_ID_CLGD5422: case CIRRUS_ID_CLGD5424: romfn = BIOS_GD5422_PATH; break; #endif - + case CIRRUS_ID_CLGD5426: romfn = BIOS_GD5426_PATH; break; - + case CIRRUS_ID_CLGD5428: if (gd54xx->vlb) romfn = BIOS_GD5428_PATH; @@ -3021,7 +3028,6 @@ static void svga->hwcursor.yoff = 32; svga->hwcursor.xoff = 0; -#if defined(DEV_BRANCH) && defined(USE_CL5422) if (id >= CIRRUS_ID_CLGD5420) { gd54xx->vclk_n[0] = 0x4a; gd54xx->vclk_d[0] = 0x2b; @@ -3041,16 +3047,6 @@ static void gd54xx->vclk_n[3] = 0x7e; gd54xx->vclk_d[3] = 0x33; } -#else - gd54xx->vclk_n[0] = 0x4a; - gd54xx->vclk_d[0] = 0x2b; - gd54xx->vclk_n[1] = 0x5b; - gd54xx->vclk_d[1] = 0x2f; - gd54xx->vclk_n[2] = 0x45; - gd54xx->vclk_d[2] = 0x30; - gd54xx->vclk_n[3] = 0x7e; - gd54xx->vclk_d[3] = 0x33; -#endif svga->extra_banks[1] = 0x8000; @@ -3072,13 +3068,19 @@ static void return gd54xx; } -#if defined(DEV_BRANCH) && defined(USE_CL5422) +static int +gd5402_available(void) +{ + return rom_present(BIOS_GD5402_PATH); +} + static int gd5420_available(void) { return rom_present(BIOS_GD5420_PATH); } +#if defined(DEV_BRANCH) && defined(USE_CL5422) static int gd5422_available(void) { @@ -3186,7 +3188,6 @@ gd54xx_force_redraw(void *p) gd54xx->svga.fullchange = changeframecount; } -#if defined(DEV_BRANCH) && defined(USE_CL5422) static const device_config_t gd5422_config[] = { { @@ -3207,7 +3208,6 @@ static const device_config_t gd5422_config[] = "","",-1 } }; -#endif static const device_config_t gd5428_config[] = { @@ -3290,7 +3290,6 @@ static const device_config_t gd5434_config[] = } }; -#if defined(DEV_BRANCH) && defined(USE_CL5422) const device_t gd5402_isa_device = { "Cirrus Logic GD-5402 (ACUMOS AVGA2)", @@ -3298,7 +3297,20 @@ const device_t gd5402_isa_device = CIRRUS_ID_CLGD5402, gd54xx_init, gd54xx_close, NULL, - gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd5402_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + NULL, +}; + +const device_t gd5402_onboard_device = +{ + "Cirrus Logic GD-5402 (ACUMOS AVGA2) (On-Board)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5402, + gd54xx_init, gd54xx_close, + NULL, + NULL, gd54xx_speed_changed, gd54xx_force_redraw, NULL, @@ -3311,12 +3323,13 @@ const device_t gd5420_isa_device = CIRRUS_ID_CLGD5420, gd54xx_init, gd54xx_close, NULL, - gd5420_available, /* Common BIOS between 5402 and 5420 */ + gd5420_available, gd54xx_speed_changed, gd54xx_force_redraw, gd5422_config, }; +#if defined(DEV_BRANCH) && defined(USE_CL5422) const device_t gd5422_isa_device = { "Cirrus Logic GD-5422", DEVICE_AT | DEVICE_ISA, diff --git a/src/video/vid_cl54xx.h b/src/video/vid_cl54xx.h index b777d28dc..10c3eea0f 100644 --- a/src/video/vid_cl54xx.h +++ b/src/video/vid_cl54xx.h @@ -1,9 +1,10 @@ /* Copyright holders: Sarah Walker see COPYING for more details */ -#if defined(DEV_BRANCH) && defined(USE_CL5422) extern const device_t gd5402_isa_device; +extern const device_t gd5402_onboard_device; extern const device_t gd5420_isa_device; +#if defined(DEV_BRANCH) && defined(USE_CL5422) extern const device_t gd5422_isa_device; extern const device_t gd5424_vlb_device; #endif diff --git a/src/video/vid_table.c b/src/video/vid_table.c index ac4a26084..5c33070f2 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.48 2020/01/20 + * Version: @(#)vid_table.c 1.0.49 2020/01/22 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -94,9 +94,9 @@ video_cards[] = { #endif { "[ISA] CGA", "cga", &cga_device }, { "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device }, -#if defined(DEV_BRANCH) && defined(USE_CL5422) { "[ISA] Cirrus Logic CL-GD 5402", "cl_gd5402_isa", &gd5402_isa_device }, { "[ISA] Cirrus Logic CL-GD 5420", "cl_gd5420_isa", &gd5420_isa_device }, +#if defined(DEV_BRANCH) && defined(USE_CL5422) { "[ISA] Cirrus Logic CL-GD 5422", "cl_gd5422_isa", &gd5422_isa_device }, #endif { "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device }, diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 15b579cf3..0e2287be5 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -565,7 +565,7 @@ CPUOBJ := cpu.o cpu_table.o \ $(DYNARECOBJ) CHIPSETOBJ := acc2168.o acer_m3a.o ali1429.o headland.o \ - intel_4x0.o neat.o opti495.o scat.o \ + intel_4x0.o neat.o opti495.o scamp.o scat.o \ sis_85c471.o sis_85c496.o \ via_mvp3.o wd76c10.o diff --git a/src/win/Makefile_ndr.mingw b/src/win/Makefile_ndr.mingw index 1ef8540d9..62713f351 100644 --- a/src/win/Makefile_ndr.mingw +++ b/src/win/Makefile_ndr.mingw @@ -571,7 +571,7 @@ CPUOBJ := cpu.o cpu_table.o \ $(DYNARECOBJ) CHIPSETOBJ := acc2168.o acer_m3a.o ali1429.o headland.o \ - intel_4x0.o neat.o opti495.o scat.o \ + intel_4x0.o neat.o opti495.o scamp.o scat.o \ sis_85c471.o sis_85c496.o \ via_mvp3.o wd76c10.o