Files
86Box/src/chipset/scat.c
David Hrdlička a505894a10 Move all include files to src/include
- 86Box's own headers go to /86box
- munt's public interface goes to /mt32emu
- all slirp headers go to /slirp (might want to consider using only its public inteface)
- single file headers from other projects go in include root
2020-03-29 19:53:29 +02:00

1624 lines
41 KiB
C

/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of Chips&Technology's SCAT (82C235) chipset.
*
* Re-worked version based on the 82C235 datasheet and errata.
*
*
*
* Authors: Original by GreatPsycho for PCem.
* Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2017-2019 GreatPsycho.
* Copyright 2017-2019 Fred N. van Kempen.
*/
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
#include <86box/device.h>
#include "cpu.h"
#include "x86.h"
#include <86box/timer.h>
#include <86box/fdd.h>
#include <86box/fdc.h>
#include <86box/keyboard.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/nmi.h>
#include <86box/port_92.h>
#include <86box/rom.h>
#include <86box/chipset.h>
#define SCAT_DMA_WAIT_STATE_CONTROL 0x01
#define SCAT_VERSION 0x40
#define SCAT_CLOCK_CONTROL 0x41
#define SCAT_PERIPHERAL_CONTROL 0x44
#define SCAT_MISCELLANEOUS_STATUS 0x45
#define SCAT_POWER_MANAGEMENT 0x46
#define SCAT_ROM_ENABLE 0x48
#define SCAT_RAM_WRITE_PROTECT 0x49
#define SCAT_SHADOW_RAM_ENABLE_1 0x4A
#define SCAT_SHADOW_RAM_ENABLE_2 0x4B
#define SCAT_SHADOW_RAM_ENABLE_3 0x4C
#define SCAT_DRAM_CONFIGURATION 0x4D
#define SCAT_EXTENDED_BOUNDARY 0x4E
#define SCAT_EMS_CONTROL 0x4F
#define SCATSX_LAPTOP_FEATURES 0x60
#define SCATSX_FAST_VIDEO_CONTROL 0x61
#define SCATSX_FAST_VIDEORAM_ENABLE 0x62
#define SCATSX_HIGH_PERFORMANCE_REFRESH 0x63
#define SCATSX_CAS_TIMING_FOR_DMA 0x64
typedef struct {
uint8_t valid, pad;
uint8_t regs_2x8;
uint8_t regs_2x9;
struct scat_t * scat;
} ems_page_t;
typedef struct scat_t {
int type;
int indx;
uint8_t regs[256];
uint8_t reg_2xA;
uint32_t xms_bound;
int external_is_RAS;
ems_page_t null_page, page[32];
mem_mapping_t low_mapping[32];
mem_mapping_t high_mapping[16];
mem_mapping_t remap_mapping[6];
mem_mapping_t efff_mapping[44];
mem_mapping_t ems_mapping[32];
} scat_t;
static const uint8_t max_map[32] = {
0, 1, 1, 1, 2, 3, 4, 8,
4, 8, 12, 16, 20, 24, 28, 32,
0, 5, 9, 13, 6, 10, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static const uint8_t max_map_sx[32] = {
0, 1, 2, 1, 3, 4, 6, 10,
5, 9, 13, 4, 8, 12, 16, 14,
18, 22, 26, 20, 24, 28, 32, 18,
20, 32, 0, 0, 0, 0, 0, 0
};
static const uint8_t scatsx_external_is_RAS[33] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0
};
static uint8_t scat_in(uint16_t port, void *priv);
static void scat_out(uint16_t port, uint8_t val, void *priv);
static void
shadow_state_update(scat_t *dev)
{
int i, val;
uint32_t base, bit, romcs, wp, shflags = 0;
for (i = 0; i < 24; i++) {
val = (dev->regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1;
base = 0xa0000 + (i << 14);
bit = (base - 0xc0000) >> 15;
romcs = 0;
wp = 0;
if (base >= 0xc0000) {
romcs = dev->regs[SCAT_ROM_ENABLE] & (1 << bit);
wp = dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << bit);
}
shflags = val ? MEM_READ_INTERNAL : (romcs ? MEM_READ_ROMCS : MEM_READ_EXTERNAL);
if (wp)
shflags |= MEM_WRITE_DISABLED;
else
shflags |= (val ? MEM_WRITE_INTERNAL : (romcs ? MEM_WRITE_ROMCS : MEM_WRITE_EXTERNAL));
mem_set_mem_state(base, 0x4000, shflags);
}
flushmmucache();
}
static void
set_xms_bound(scat_t *dev, uint8_t val)
{
uint32_t xms_max = ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && ((val & 0x10) != 0)) || (dev->regs[SCAT_VERSION] >= 4) ? 0xfe0000 : 0xfc0000;
int i;
switch (val & 0x0f) {
case 1:
dev->xms_bound = 0x100000;
break;
case 2:
dev->xms_bound = 0x140000;
break;
case 3:
dev->xms_bound = 0x180000;
break;
case 4:
dev->xms_bound = 0x200000;
break;
case 5:
dev->xms_bound = 0x300000;
break;
case 6:
dev->xms_bound = 0x400000;
break;
case 7:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x600000 : 0x500000;
break;
case 8:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x800000 : 0x700000;
break;
case 9:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xa00000 : 0x800000;
break;
case 10:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xc00000 : 0x900000;
break;
case 11:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0xe00000 : 0xa00000;
break;
case 12:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xb00000;
break;
case 13:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xc00000;
break;
case 14:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xd00000;
break;
case 15:
dev->xms_bound = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? xms_max : 0xf00000;
break;
default:
dev->xms_bound = xms_max;
break;
}
if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) && (val & 0x40) == 0 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3) ||
(((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)) {
if ((val & 0x0f) == 0 || dev->xms_bound > 0x160000)
dev->xms_bound = 0x160000;
if (dev->xms_bound > 0x100000)
mem_set_mem_state(0x100000, dev->xms_bound - 0x100000,
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
if (dev->xms_bound < 0x160000)
mem_set_mem_state(dev->xms_bound, 0x160000 - dev->xms_bound,
MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
} else {
if (dev->xms_bound > xms_max)
dev->xms_bound = xms_max;
if (dev->xms_bound > 0x100000)
mem_set_mem_state(0x100000, dev->xms_bound - 0x100000,
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
if (dev->xms_bound < ((uint32_t)mem_size << 10))
mem_set_mem_state(dev->xms_bound, (mem_size << 10) - dev->xms_bound,
MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
}
mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000,
((dev->regs[SCAT_VERSION] & 0xf0) != 0 && ((val & 0x10) != 0)) ||
(dev->regs[SCAT_VERSION] >= 4) ? 0x60000 : 0x40000);
if (dev->regs[SCAT_VERSION] & 0xf0) {
for (i = 0; i < 8; i++) {
if (val & 0x10)
mem_mapping_disable(&dev->high_mapping[i]);
else
mem_mapping_enable(&dev->high_mapping[i]);
}
}
}
static uint32_t
get_addr(scat_t *dev, uint32_t addr, ems_page_t *p)
{
#if 1
int nbanks_2048k, nbanks_512k;
uint32_t addr2;
int nbank;
#else
uint32_t nbanks_2048k, nbanks_512k, addr2, nbank;
#endif
if (p && p->valid && (dev->regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80))
addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14;
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) {
switch((dev->regs[SCAT_EXTENDED_BOUNDARY] & ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 0x40 : 0)) | (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f)) {
case 0x41:
nbank = addr >> 19;
if (nbank < 4)
nbank = 1;
else if (nbank == 4)
nbank = 0;
else
nbank -= 3;
break;
case 0x42:
nbank = addr >> 19;
if (nbank < 8)
nbank = 1 + (nbank >> 2);
else if (nbank == 8)
nbank = 0;
else
nbank -= 6;
break;
case 0x43:
nbank = addr >> 19;
if (nbank < 12)
nbank = 1 + (nbank >> 2);
else if (nbank == 12)
nbank = 0;
else
nbank -= 9;
break;
case 0x44:
nbank = addr >> 19;
if (nbank < 4)
nbank = 2;
else if (nbank < 6)
nbank -= 4;
else
nbank -= 3;
break;
case 0x45:
nbank = addr >> 19;
if (nbank < 8)
nbank = 2 + (nbank >> 2);
else if (nbank < 10)
nbank -= 8;
else
nbank -= 6;
break;
default:
nbank = addr >> (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8 && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) ? 19 : 21);
break;
}
nbank &= (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3;
if ((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 &&
(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3 &&
nbank == 2 && (addr & 0x7ffff) < 0x60000 && mem_size > 640) {
nbank = 1;
addr ^= 0x70000;
}
if (dev->external_is_RAS && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) {
if (nbank == 3)
nbank = 7;
else
return 0xffffffff;
} else if (!dev->external_is_RAS && dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) {
switch(nbank) {
case 7:
nbank = 3;
break;
/* Note - In the following cases, the chipset accesses multiple memory banks
at the same time, so it's impossible to predict which memory bank
is actually accessed. */
case 5:
case 1:
nbank = 1;
break;
case 3:
nbank = 2;
break;
default:
nbank = 0;
break;
}
}
if ((dev->regs[SCAT_VERSION] & 0x0f) > 3 && (mem_size > 2048) && (mem_size & 1536)) {
if ((mem_size & 1536) == 512) {
if (nbank == 0)
addr &= 0x7ffff;
else
addr = 0x80000 + ((addr & 0x1fffff) | ((nbank - 1) << 21));
} else {
if (nbank < 2)
addr = (addr & 0x7ffff) | (nbank << 19);
else
addr = 0x100000 + ((addr & 0x1fffff) | ((nbank - 2) << 21));
}
} else {
if (mem_size <= ((dev->regs[SCAT_VERSION] & 0x0f) > 3 ? 2048 : 4096) && (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) < 8) || dev->external_is_RAS)) {
nbanks_2048k = 0;
nbanks_512k = mem_size >> 9;
} else {
nbanks_2048k = mem_size >> 11;
nbanks_512k = (mem_size & 1536) >> 9;
}
if (nbank < nbanks_2048k || (nbanks_2048k > 0 && nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7))) {
addr &= 0x1fffff;
addr |= (nbank << 21);
} else if (nbank < nbanks_2048k + nbanks_512k || nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7)) {
addr &= 0x7ffff;
addr |= (nbanks_2048k << 21) | ((nbank - nbanks_2048k) << 19);
} else {
addr &= 0x1ffff;
addr |= (nbanks_2048k << 21) | (nbanks_512k << 19) | ((nbank - nbanks_2048k - nbanks_512k) << 17);
}
}
} else {
switch(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) {
case 0x02:
case 0x04:
nbank = addr >> 19;
if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) {
nbank = (addr >> 10) & 1;
addr2 = addr >> 11;
} else
addr2 = addr >> 10;
break;
case 0x03:
nbank = addr >> 19;
if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) {
nbank = (addr >> 10) & 1;
addr2 = addr >> 11;
} else if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) == 2 && (addr & 0x7ffff) < 0x60000) {
addr ^= 0x1f0000;
nbank = (addr >> 10) & 1;
addr2 = addr >> 11;
} else
addr2 = addr >> 10;
break;
case 0x05:
nbank = addr >> 19;
if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) {
nbank = (addr >> 10) & 3;
addr2 = addr >> 12;
} else
addr2 = addr >> 10;
break;
case 0x06:
nbank = addr >> 19;
if (nbank < 2) {
nbank = (addr >> 10) & 1;
addr2 = addr >> 11;
} else {
nbank = 2 + ((addr - 0x100000) >> 21);
addr2 = (addr - 0x100000) >> 11;
}
break;
case 0x07:
case 0x0f:
nbank = addr >> 19;
if (nbank < 2) {
nbank = (addr >> 10) & 1;
addr2 = addr >> 11;
} else if (nbank < 10) {
nbank = 2 + (((addr - 0x100000) >> 11) & 1);
addr2 = (addr - 0x100000) >> 12;
} else {
nbank = 4 + ((addr - 0x500000) >> 21);
addr2 = (addr - 0x500000) >> 11;
}
break;
case 0x08:
nbank = addr >> 19;
if (nbank < 4) {
nbank = 1;
addr2 = addr >> 11;
} else if (nbank == 4) {
nbank = 0;
addr2 = addr >> 10;
} else {
nbank -= 3;
addr2 = addr >> 10;
}
break;
case 0x09:
nbank = addr >> 19;
if (nbank < 8) {
nbank = 1 + ((addr >> 11) & 1);
addr2 = addr >> 12;
} else if (nbank == 8) {
nbank = 0;
addr2 = addr >> 10;
} else {
nbank -= 6;
addr2 = addr >> 10;
}
break;
case 0x0a:
nbank = addr >> 19;
if (nbank < 8) {
nbank = 1 + ((addr >> 11) & 1);
addr2 = addr >> 12;
} else if (nbank < 12) {
nbank = 3;
addr2 = addr >> 11;
} else if (nbank == 12) {
nbank = 0;
addr2 = addr >> 10;
} else {
nbank -= 9;
addr2 = addr >> 10;
}
break;
case 0x0b:
nbank = addr >> 21;
addr2 = addr >> 11;
break;
case 0x0c:
case 0x0d:
nbank = addr >> 21;
if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) {
nbank = (addr >> 11) & 1;
addr2 = addr >> 12;
} else
addr2 = addr >> 11;
break;
case 0x0e:
case 0x13:
nbank = addr >> 21;
if ((nbank & (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) {
nbank = (addr >> 11) & 3;
addr2 = addr >> 13;
} else
addr2 = addr >> 11;
break;
case 0x10:
case 0x11:
nbank = addr >> 19;
if (nbank < 2) {
nbank = (addr >> 10) & 1;
addr2 = addr >> 11;
} else if (nbank < 10) {
nbank = 2 + (((addr - 0x100000) >> 11) & 1);
addr2 = (addr - 0x100000) >> 12;
} else if (nbank < 18) {
nbank = 4 + (((addr - 0x500000) >> 11) & 1);
addr2 = (addr - 0x500000) >> 12;
} else {
nbank = 6 + ((addr - 0x900000) >> 21);
addr2 = (addr - 0x900000) >> 11;
}
break;
case 0x12:
nbank = addr >> 19;
if (nbank < 2) {
nbank = (addr >> 10) & 1;
addr2 = addr >> 11;
} else if (nbank < 10) {
nbank = 2 + (((addr - 0x100000) >> 11) & 1);
addr2 = (addr - 0x100000) >> 12;
} else {
nbank = 4 + (((addr - 0x500000) >> 11) & 3);
addr2 = (addr - 0x500000) >> 13;
}
break;
case 0x14:
case 0x15:
nbank = addr >> 21;
if ((nbank & 7) < 4) {
nbank = (addr >> 11) & 3;
addr2 = addr >> 13;
} else if ((nbank & 7) < 6) {
nbank = 4 + (((addr - 0x800000) >> 11) & 1);
addr2 = (addr - 0x800000) >> 12;
} else {
nbank = 6 + (((addr - 0xc00000) >> 11) & 3);
addr2 = (addr - 0xc00000) >> 13;
}
break;
case 0x16:
nbank = ((addr >> 21) & 4) | ((addr >> 11) & 3);
addr2 = addr >> 13;
break;
case 0x17:
if (dev->external_is_RAS && (addr & 0x800) == 0)
return 0xffffffff;
nbank = addr >> 19;
if (nbank < 2) {
nbank = (addr >> 10) & 1;
addr2 = addr >> 11;
} else {
nbank = 2 + ((addr - 0x100000) >> 23);
addr2 = (addr - 0x100000) >> 12;
}
break;
case 0x18:
if (dev->external_is_RAS && (addr & 0x800) == 0)
return 0xffffffff;
nbank = addr >> 21;
if (nbank < 4) {
nbank = 1;
addr2 = addr >> 12;
} else if (nbank == 4) {
nbank = 0;
addr2 = addr >> 11;
} else {
nbank -= 3;
addr2 = addr >> 11;
}
break;
case 0x19:
if (dev->external_is_RAS && (addr & 0x800) == 0)
return 0xffffffff;
nbank = addr >> 23;
if ((nbank & 3) < 2) {
nbank = (addr >> 12) & 1;
addr2 = addr >> 13;
} else
addr2 = addr >> 12;
break;
default:
if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 6) {
nbank = addr >> 19;
addr2 = (addr >> 10) & 0x1ff;
} else if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 0x17) {
nbank = addr >> 21;
addr2 = (addr >> 11) & 0x3ff;
} else {
nbank = addr >> 23;
addr2 = (addr >> 12) & 0x7ff;
}
break;
}
nbank &= (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3;
if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) > 0x16 && nbank == 3)
return 0xffffffff;
if (dev->external_is_RAS && (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) {
if (nbank == 3)
nbank = 7;
else
return 0xffffffff;
} else if (!dev->external_is_RAS && dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x80) {
switch(nbank) {
case 7:
nbank = 3;
break;
/* Note - In the following cases, the chipset accesses multiple memory banks
at the same time, so it's impossible to predict which memory bank
is actually accessed. */
case 5:
case 1:
nbank = 1;
break;
case 3:
nbank = 2;
break;
default:
nbank = 0;
break;
}
}
switch(mem_size & ~511) {
case 1024:
case 1536:
addr &= 0x3ff;
if (nbank < 2)
addr |= (nbank << 10) | ((addr2 & 0x1ff) << 11);
else
addr |= ((addr2 & 0x1ff) << 10) | (nbank << 19);
break;
case 2048:
if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 5) {
addr &= 0x3ff;
if (nbank < 4)
addr |= (nbank << 10) | ((addr2 & 0x1ff) << 12);
else
addr |= ((addr2 & 0x1ff) << 10) | (nbank << 19);
} else {
addr &= 0x7ff;
addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21);
}
break;
case 2560:
if (nbank == 0)
addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10);
else {
addr &= 0x7ff;
addr2 &= 0x3ff;
addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21));
}
break;
case 3072:
if (nbank < 2)
addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11);
else
addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21));
break;
case 4096:
case 6144:
addr &= 0x7ff;
if (nbank < 2)
addr |= (nbank << 11) | ((addr2 & 0x3ff) << 12);
else
addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21);
break;
case 4608:
if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) >= 8 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) <= 0x0a) || ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 0x18)) {
if (nbank == 0)
addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10);
else if (nbank < 3)
addr = 0x80000 + ((addr & 0x7ff) | ((nbank - 1) << 11) | ((addr2 & 0x3ff) << 12));
else
addr = 0x480000 + ((addr & 0x3ff) | ((addr2 & 0x1ff) << 10) | ((nbank - 3) << 19));
} else if (nbank == 0)
addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10);
else {
addr &= 0x7ff;
addr2 &= 0x3ff;
addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21));
}
break;
case 5120:
case 7168:
if (nbank < 2)
addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11);
else if (nbank < 4)
addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11));
else
addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21));
break;
case 6656:
if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) >= 8 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) <= 0x0a) || ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 0x18)) {
if (nbank == 0)
addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10);
else if (nbank < 3)
addr = 0x80000 + ((addr & 0x7ff) | ((nbank - 1) << 11) | ((addr2 & 0x3ff) << 12));
else if (nbank == 3)
addr = 0x480000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11));
else
addr = 0x680000 + ((addr & 0x3ff) | ((addr2 & 0x1ff) << 10) | ((nbank - 4) << 19));
} else if (nbank == 0)
addr = (addr & 0x3ff) | ((addr2 & 0x1ff) << 10);
else if (nbank == 1) {
addr &= 0x7ff;
addr2 &= 0x3ff;
addr = addr + 0x80000 + (addr2 << 11);
} else {
addr &= 0x7ff;
addr2 &= 0x3ff;
addr = addr + 0x280000 + ((addr2 << 12) | ((nbank & 1) << 11) | (((nbank - 2) & 6) << 21));
}
break;
case 8192:
addr &= 0x7ff;
if (nbank < 4)
addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13);
else
addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21);
break;
case 9216:
if (nbank < 2)
addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11);
else if (dev->external_is_RAS) {
if (nbank < 6)
addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11));
else
addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21));
} else
addr = 0x100000 + ((addr & 0xfff) | ((addr2 & 0x7ff) << 12) | ((nbank - 2) << 23));
break;
case 10240:
if (dev->external_is_RAS) {
addr &= 0x7ff;
if (nbank < 4)
addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13);
else
addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21);
} else if (nbank == 0)
addr = (addr & 0x7ff) | ((addr2 & 0x3ff) << 11);
else {
addr &= 0xfff;
addr2 &= 0x7ff;
addr = addr + 0x200000 + ((addr2 << 12) | ((nbank - 1) << 23));
}
break;
case 11264:
if (nbank < 2)
addr = (addr & 0x3ff) | (nbank << 10) | ((addr2 & 0x1ff) << 11);
else if (nbank < 6)
addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 12) | ((nbank & 1) << 11));
else
addr = 0x100000 + ((addr & 0x7ff) | ((addr2 & 0x3ff) << 11) | ((nbank - 2) << 21));
break;
case 12288:
if (dev->external_is_RAS) {
addr &= 0x7ff;
if (nbank < 4)
addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13);
else if (nbank < 6)
addr |= ((nbank & 1) << 11) | ((addr2 & 0x3ff) << 12) | ((nbank & 4) << 21);
else
addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21);
} else {
if (nbank < 2)
addr = (addr & 0x7ff) | (nbank << 11) | ((addr2 & 0x3ff) << 12);
else
addr = 0x400000 + ((addr & 0xfff) | ((addr2 & 0x7ff) << 12) | ((nbank - 2) << 23));
}
break;
case 13312:
if (nbank < 2)
addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11);
else if (nbank < 4)
addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11));
else
addr = 0x500000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 13) | ((nbank & 3) << 11));
break;
case 14336:
addr &= 0x7ff;
if (nbank < 4)
addr |= (nbank << 11) | ((addr2 & 0x3ff) << 13);
else if (nbank < 6)
addr |= ((nbank & 1) << 11) | ((addr2 & 0x3ff) << 12) | ((nbank & 4) << 21);
else
addr |= ((addr2 & 0x3ff) << 11) | (nbank << 21);
break;
case 16384:
if (dev->external_is_RAS) {
addr &= 0x7ff;
addr2 &= 0x3ff;
addr |= ((nbank & 3) << 11) | (addr2 << 13) | ((nbank & 4) << 21);
} else {
addr &= 0xfff;
addr2 &= 0x7ff;
if (nbank < 2)
addr |= (addr2 << 13) | (nbank << 12);
else
addr |= (addr2 << 12) | (nbank << 23);
}
break;
default:
if (mem_size < 2048 || ((mem_size & 1536) == 512) || (mem_size == 2048 && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 6)) {
addr &= 0x3ff;
addr2 &= 0x1ff;
addr |= (addr2 << 10) | (nbank << 19);
} else if (mem_size < 8192 || (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 0x17) {
addr &= 0x7ff;
addr2 &= 0x3ff;
addr |= (addr2 << 11) | (nbank << 21);
} else {
addr &= 0xfff;
addr2 &= 0x7ff;
addr |= (addr2 << 12) | (nbank << 23);
}
break;
}
}
return addr;
}
static void
set_global_EMS_state(scat_t *dev, int state)
{
uint32_t base_addr, virt_addr;
int i, conf;
for (i = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 24; i < 32; i++) {
base_addr = (i + 16) << 14;
if (i >= 24)
base_addr += 0x30000;
if (state && (dev->page[i].regs_2x9 & 0x80)) {
virt_addr = get_addr(dev, base_addr, &dev->page[i]);
if (i < 24)
mem_mapping_disable(&dev->efff_mapping[i]);
else
mem_mapping_disable(&dev->efff_mapping[i + 12]);
mem_mapping_enable(&dev->ems_mapping[i]);
if (virt_addr < ((uint32_t)mem_size << 10))
mem_mapping_set_exec(&dev->ems_mapping[i], ram + virt_addr);
else
mem_mapping_set_exec(&dev->ems_mapping[i], NULL);
} else {
mem_mapping_set_exec(&dev->ems_mapping[i], ram + base_addr);
mem_mapping_disable(&dev->ems_mapping[i]);
conf = (dev->regs[SCAT_VERSION] & 0xf0) ? (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f)
: (dev->regs[SCAT_DRAM_CONFIGURATION] & 0xf) |
((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2);
if (i < 24) {
if (conf > 1 || (conf == 1 && i < 16))
mem_mapping_enable(&dev->efff_mapping[i]);
else
mem_mapping_disable(&dev->efff_mapping[i]);
} else if (conf > 3 || ((dev->regs[SCAT_VERSION] & 0xf0) != 0 && conf == 2))
mem_mapping_enable(&dev->efff_mapping[i + 12]);
else
mem_mapping_disable(&dev->efff_mapping[i + 12]);
}
}
flushmmucache();
}
static void
memmap_state_update(scat_t *dev)
{
uint32_t addr;
int i;
for (i = (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0 : 16); i < 44; i++) {
addr = get_addr(dev, 0x40000 + (i << 14), NULL);
mem_mapping_set_exec(&dev->efff_mapping[i],
addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL);
}
addr = get_addr(dev, 0, NULL);
mem_mapping_set_exec(&dev->low_mapping[0],
addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL);
addr = get_addr(dev, 0xf0000, NULL);
mem_mapping_set_exec(&dev->low_mapping[1],
addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL);
for (i = 2; i < 32; i++) {
addr = get_addr(dev, i << 19, NULL);
mem_mapping_set_exec(&dev->low_mapping[i],
addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL);
}
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) {
for (i = 0; i < max_map[(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) |
((dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2)]; i++)
mem_mapping_enable(&dev->low_mapping[i]);
for (; i < 32; i++)
mem_mapping_disable(&dev->low_mapping[i]);
for (i = 24; i < 36; i++) {
if (((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) | (dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40)) < 4)
mem_mapping_disable(&dev->efff_mapping[i]);
else
mem_mapping_enable(&dev->efff_mapping[i]);
}
} else {
for (i = 0; i < max_map_sx[dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f]; i++)
mem_mapping_enable(&dev->low_mapping[i]);
for (; i < 32; i++)
mem_mapping_disable(&dev->low_mapping[i]);
for(i = 24; i < 36; i++) {
if ((dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) < 2 || (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)
mem_mapping_disable(&dev->efff_mapping[i]);
else
mem_mapping_enable(&dev->efff_mapping[i]);
}
}
if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) &&
(dev->regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((dev->regs[SCAT_VERSION] & 0xf0) != 0)) {
if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) &&
(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) == 3) ||
(((dev->regs[SCAT_VERSION] & 0xf0) != 0) && (dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) == 3)) {
mem_mapping_disable(&dev->low_mapping[2]);
for (i = 0; i < 6; i++) {
addr = get_addr(dev, 0x100000 + (i << 16), NULL);
mem_mapping_set_exec(&dev->remap_mapping[i],
addr < ((uint32_t)mem_size << 10) ? ram + addr : NULL);
mem_mapping_enable(&dev->remap_mapping[i]);
}
} else {
for (i = 0; i < 6; i++)
mem_mapping_disable(&dev->remap_mapping[i]);
if ((((dev->regs[SCAT_VERSION] & 0xf0) == 0) &&
(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x0f) > 4) ||
(((dev->regs[SCAT_VERSION] & 0xf0) != 0) &&
(dev->regs[SCAT_DRAM_CONFIGURATION] & 0x1f) > 3))
mem_mapping_enable(&dev->low_mapping[2]);
}
} else {
for (i = 0; i < 6; i++)
mem_mapping_disable(&dev->remap_mapping[i]);
mem_mapping_enable(&dev->low_mapping[2]);
}
set_global_EMS_state(dev, dev->regs[SCAT_EMS_CONTROL] & 0x80);
flushmmucache_cr3();
}
static void
scat_out(uint16_t port, uint8_t val, void *priv)
{
scat_t *dev = (scat_t *)priv;
uint8_t reg_valid = 0,
shadow_update = 0,
map_update = 0,
indx;
uint32_t base_addr, virt_addr;
switch (port) {
case 0x22:
dev->indx = val;
break;
case 0x23:
switch (dev->indx) {
case SCAT_DMA_WAIT_STATE_CONTROL:
case SCAT_CLOCK_CONTROL:
case SCAT_PERIPHERAL_CONTROL:
reg_valid = 1;
break;
case SCAT_EMS_CONTROL:
io_removehandler(0x0208, 0x0003, scat_in, NULL, NULL, scat_out, NULL, NULL, dev);
io_removehandler(0x0218, 0x0003, scat_in, NULL, NULL, scat_out, NULL, NULL, dev);
if (val & 0x40) {
if (val & 1)
io_sethandler(0x0218, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev);
else
io_sethandler(0x0208, 3, scat_in, NULL, NULL, scat_out, NULL, NULL, dev);
}
set_global_EMS_state(dev, val & 0x80);
reg_valid = 1;
break;
case SCAT_POWER_MANAGEMENT:
/* TODO - Only use AUX parity disable bit for this version.
Other bits should be implemented later. */
val &= (dev->regs[SCAT_VERSION] & 0xf0) == 0 ? 0x40 : 0x60;
reg_valid = 1;
break;
case SCAT_DRAM_CONFIGURATION:
map_update = 1;
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) {
cpu_waitstates = (val & 0x70) == 0 ? 1 : 2;
cpu_update_waitstates();
}
reg_valid = 1;
break;
case SCAT_EXTENDED_BOUNDARY:
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) {
if (dev->regs[SCAT_VERSION] < 4) {
val &= 0xbf;
set_xms_bound(dev, val & 0x0f);
} else {
val = (val & 0x7f) | 0x80;
set_xms_bound(dev, val & 0x4f);
}
} else
set_xms_bound(dev, val & 0x1f);
mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL :
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
if ((val ^ dev->regs[SCAT_EXTENDED_BOUNDARY]) & 0xc0)
map_update = 1;
reg_valid = 1;
break;
case SCAT_ROM_ENABLE:
case SCAT_RAM_WRITE_PROTECT:
case SCAT_SHADOW_RAM_ENABLE_1:
case SCAT_SHADOW_RAM_ENABLE_2:
case SCAT_SHADOW_RAM_ENABLE_3:
reg_valid = 1;
shadow_update = 1;
break;
case SCATSX_LAPTOP_FEATURES:
if ((dev->regs[SCAT_VERSION] & 0xf0) != 0) {
val = (val & ~8) | (dev->regs[SCATSX_LAPTOP_FEATURES] & 8);
reg_valid = 1;
}
break;
case SCATSX_FAST_VIDEO_CONTROL:
case SCATSX_FAST_VIDEORAM_ENABLE:
case SCATSX_HIGH_PERFORMANCE_REFRESH:
case SCATSX_CAS_TIMING_FOR_DMA:
if ((dev->regs[SCAT_VERSION] & 0xf0) != 0)
reg_valid = 1;
break;
default:
break;
}
if (reg_valid)
dev->regs[dev->indx] = val;
if (shadow_update)
shadow_state_update(dev);
if (map_update)
memmap_state_update(dev);
break;
case 0x208:
case 0x218:
if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0)
indx = dev->reg_2xA & 0x1f;
else
indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24;
dev->page[indx].regs_2x8 = val;
base_addr = (indx + 16) << 14;
if (indx >= 24)
base_addr += 0x30000;
if ((dev->regs[SCAT_EMS_CONTROL] & 0x80) && (dev->page[indx].regs_2x9 & 0x80)) {
virt_addr = get_addr(dev, base_addr, &dev->page[indx]);
if (virt_addr < ((uint32_t)mem_size << 10))
mem_mapping_set_exec(&dev->ems_mapping[indx], ram + virt_addr);
else
mem_mapping_set_exec(&dev->ems_mapping[indx], NULL);
flushmmucache();
}
}
break;
case 0x209:
case 0x219:
if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0)
indx = dev->reg_2xA & 0x1f;
else
indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24;
dev->page[indx].regs_2x9 = val;
base_addr = (indx + 16) << 14;
if (indx >= 24)
base_addr += 0x30000;
if (dev->regs[SCAT_EMS_CONTROL] & 0x80) {
if (val & 0x80) {
virt_addr = get_addr(dev, base_addr, &dev->page[indx]);
if (indx < 24)
mem_mapping_disable(&dev->efff_mapping[indx]);
else
mem_mapping_disable(&dev->efff_mapping[indx + 12]);
if (virt_addr < ((uint32_t)mem_size << 10))
mem_mapping_set_exec(&dev->ems_mapping[indx], ram + virt_addr);
else
mem_mapping_set_exec(&dev->ems_mapping[indx], NULL);
mem_mapping_enable(&dev->ems_mapping[indx]);
} else {
mem_mapping_set_exec(&dev->ems_mapping[indx], ram + base_addr);
mem_mapping_disable(&dev->ems_mapping[indx]);
if (indx < 24)
mem_mapping_enable(&dev->efff_mapping[indx]);
else
mem_mapping_enable(&dev->efff_mapping[indx + 12]);
}
flushmmucache();
}
if (dev->reg_2xA & 0x80)
dev->reg_2xA = (dev->reg_2xA & 0xe0) | ((dev->reg_2xA + 1) & (((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? 0x1f : 3));
}
break;
case 0x20a:
case 0x21a:
if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4)))
dev->reg_2xA = ((dev->regs[SCAT_VERSION] & 0xf0) == 0) ? val : val & 0xc3;
break;
}
}
static uint8_t
scat_in(uint16_t port, void *priv)
{
scat_t *dev = (scat_t *)priv;
uint8_t ret = 0xff, indx;
switch (port) {
case 0x23:
switch (dev->indx) {
case SCAT_MISCELLANEOUS_STATUS:
ret = (dev->regs[dev->indx] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5);
break;
case SCAT_DRAM_CONFIGURATION:
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0)
ret = (dev->regs[dev->indx] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10);
else
ret = dev->regs[dev->indx];
break;
case SCAT_EXTENDED_BOUNDARY:
ret = dev->regs[dev->indx];
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0) {
if ((dev->regs[SCAT_VERSION] & 0x0f) >= 4)
ret |= 0x80;
else
ret &= 0xaf;
}
break;
default:
ret = dev->regs[dev->indx];
break;
}
break;
case 0x208:
case 0x218:
if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0)
indx = dev->reg_2xA & 0x1f;
else
indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24;
ret = dev->page[indx].regs_2x8;
}
break;
case 0x209:
case 0x219:
if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
if ((dev->regs[SCAT_VERSION] & 0xf0) == 0)
indx = dev->reg_2xA & 0x1f;
else
indx = ((dev->reg_2xA & 0x40) >> 4) + (dev->reg_2xA & 0x3) + 24;
ret = dev->page[indx].regs_2x9;
}
break;
case 0x20a:
case 0x21a:
if ((dev->regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4)))
ret = dev->reg_2xA;
break;
}
return ret;
}
static uint8_t
mem_read_scatb(uint32_t addr, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
scat_t *dev = (scat_t *)page->scat;
uint8_t val = 0xff;
addr = get_addr(dev, addr, page);
if (addr < ((uint32_t)mem_size << 10))
val = ram[addr];
return val;
}
static uint16_t
mem_read_scatw(uint32_t addr, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
scat_t *dev = (scat_t *)page->scat;
uint16_t val = 0xffff;
addr = get_addr(dev, addr, page);
if (addr < ((uint32_t)mem_size << 10))
val = *(uint16_t *)&ram[addr];
return val;
}
static uint32_t
mem_read_scatl(uint32_t addr, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
scat_t *dev = (scat_t *)page->scat;
uint32_t val = 0xffffffff;
addr = get_addr(dev, addr, page);
if (addr < ((uint32_t)mem_size << 10))
val = *(uint32_t *)&ram[addr];
return val;
}
static void
mem_write_scatb(uint32_t addr, uint8_t val, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
scat_t *dev;
uint32_t oldaddr = addr, chkaddr;
if (page == NULL)
dev = NULL;
else
dev = (scat_t *)page->scat;
if (dev == NULL)
chkaddr = oldaddr;
else {
addr = get_addr(dev, addr, page);
chkaddr = addr;
}
if (chkaddr >= 0xc0000 && chkaddr < 0x100000) {
if ((dev == NULL) || (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))))
return;
}
if (addr < ((uint32_t)mem_size << 10))
ram[addr] = val;
}
static void
mem_write_scatw(uint32_t addr, uint16_t val, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
scat_t *dev;
uint32_t oldaddr = addr, chkaddr;
if (page == NULL)
dev = NULL;
else
dev = (scat_t *)page->scat;
if (dev == NULL)
chkaddr = oldaddr;
else {
addr = get_addr(dev, addr, page);
chkaddr = addr;
}
if (chkaddr >= 0xc0000 && chkaddr < 0x100000) {
if (dev != NULL && (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))))
return;
}
if (addr < ((uint32_t)mem_size << 10))
*(uint16_t *)&ram[addr] = val;
}
static void
mem_write_scatl(uint32_t addr, uint32_t val, void *priv)
{
ems_page_t *page = (ems_page_t *)priv;
scat_t *dev;
uint32_t oldaddr = addr, chkaddr;
if (page == NULL)
dev = NULL;
else
dev = (scat_t *)page->scat;
if (dev == NULL)
chkaddr = oldaddr;
else {
addr = get_addr(dev, addr, page);
chkaddr = addr;
}
if (chkaddr >= 0xc0000 && chkaddr < 0x100000) {
if (dev != NULL && (dev->regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xc0000) >> 15))))
return;
}
if (addr < ((uint32_t)mem_size << 10))
*(uint32_t *)&ram[addr] = val;
}
static void
scat_close(void *priv)
{
scat_t *dev = (scat_t *)priv;
free(dev);
}
static void *
scat_init(const device_t *info)
{
scat_t *dev;
uint32_t i, k;
int sx;
dev = (scat_t *)malloc(sizeof(scat_t));
memset(dev, 0x00, sizeof(scat_t));
dev->type = info->local;
sx = (dev->type == 32) ? 1 : 0;
for (i = 0; i < sizeof(dev->regs); i++)
dev->regs[i] = 0xff;
if (sx) {
dev->regs[SCAT_VERSION] = 0x13;
dev->regs[SCAT_CLOCK_CONTROL] = 6;
dev->regs[SCAT_PERIPHERAL_CONTROL] = 0;
dev->regs[SCAT_DRAM_CONFIGURATION] = 1;
dev->regs[SCATSX_LAPTOP_FEATURES] = 0;
dev->regs[SCATSX_FAST_VIDEO_CONTROL] = 0;
dev->regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0;
dev->regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8;
dev->regs[SCATSX_CAS_TIMING_FOR_DMA] = 3;
} else {
switch(dev->type) {
case 4:
dev->regs[SCAT_VERSION] = 4;
break;
default:
dev->regs[SCAT_VERSION] = 1;
break;
}
dev->regs[SCAT_CLOCK_CONTROL] = 2;
dev->regs[SCAT_PERIPHERAL_CONTROL] = 0x80;
dev->regs[SCAT_DRAM_CONFIGURATION] = cpu_waitstates == 1 ? 2 : 0x12;
}
dev->regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0;
dev->regs[SCAT_MISCELLANEOUS_STATUS] = 0x37;
dev->regs[SCAT_ROM_ENABLE] = 0xc0;
dev->regs[SCAT_RAM_WRITE_PROTECT] = 0;
dev->regs[SCAT_POWER_MANAGEMENT] = 0;
dev->regs[SCAT_SHADOW_RAM_ENABLE_1] = 0;
dev->regs[SCAT_SHADOW_RAM_ENABLE_2] = 0;
dev->regs[SCAT_SHADOW_RAM_ENABLE_3] = 0;
dev->regs[SCAT_EXTENDED_BOUNDARY] = 0;
dev->regs[SCAT_EMS_CONTROL] = 0;
/* Disable all system mappings, we will override them. */
mem_mapping_disable(&ram_low_mapping);
if (! sx)
mem_mapping_disable(&ram_mid_mapping);
mem_mapping_disable(&ram_high_mapping);
#if 0
mem_mapping_disable(&bios_mapping);
#endif
k = (sx) ? 0x80000 : 0x40000;
dev->null_page.valid = 0;
dev->null_page.regs_2x8 = 0xff;
dev->null_page.regs_2x9 = 0xff;
dev->null_page.scat = dev;
mem_mapping_add(&dev->low_mapping[0], 0, k,
mem_read_scatb, mem_read_scatw, mem_read_scatl,
mem_write_scatb, mem_write_scatw, mem_write_scatl,
ram, MEM_MAPPING_INTERNAL, &dev->null_page);
mem_mapping_add(&dev->low_mapping[1], 0xf0000, 0x10000,
mem_read_scatb, mem_read_scatw, mem_read_scatl,
mem_write_scatb, mem_write_scatw, mem_write_scatl,
ram + 0xf0000, MEM_MAPPING_INTERNAL, &dev->null_page);
for (i = 2; i < 32; i++) {
mem_mapping_add(&dev->low_mapping[i], (i << 19), 0x80000,
mem_read_scatb, mem_read_scatw, mem_read_scatl,
mem_write_scatb, mem_write_scatw, mem_write_scatl,
ram + (i<<19), MEM_MAPPING_INTERNAL, &dev->null_page);
}
if (sx) {
i = 16;
k = 0x40000;
} else {
i = 0;
k = (dev->regs[SCAT_VERSION] < 4) ? 0x40000 : 0x60000;
}
mem_mapping_set_addr(&dev->low_mapping[31], 0xf80000, k);
for (; i < 44; i++) {
mem_mapping_add(&dev->efff_mapping[i], 0x40000 + (i << 14), 0x4000,
mem_read_scatb, mem_read_scatw, mem_read_scatl,
mem_write_scatb, mem_write_scatw, mem_write_scatl,
mem_size > (256 + (i << 4)) ? ram + 0x40000 + (i << 14) : NULL,
MEM_MAPPING_INTERNAL, &dev->null_page);
if (sx)
mem_mapping_enable(&dev->efff_mapping[i]);
}
if (sx) {
for (i = 24; i < 32; i++) {
dev->page[i].valid = 1;
dev->page[i].regs_2x8 = 0xff;
dev->page[i].regs_2x9 = 0x03;
dev->page[i].scat = dev;
mem_mapping_add(&dev->ems_mapping[i], (i + 28) << 14, 0x04000,
mem_read_scatb, mem_read_scatw, mem_read_scatl,
mem_write_scatb, mem_write_scatw, mem_write_scatl,
ram + ((i + 28) << 14), 0, &dev->page[i]);
mem_mapping_disable(&dev->ems_mapping[i]);
}
for (i = 0; i < 16; i++) {
mem_mapping_add(&dev->high_mapping[i], (i << 14) + 0xfc0000, 0x04000,
mem_read_bios, mem_read_biosw, mem_read_biosl,
mem_write_null, mem_write_nullw, mem_write_nulll,
rom + ((i << 14) & biosmask), 0, NULL);
mem_mapping_enable(&dev->high_mapping[i]);
}
} else {
for (i = 0; i < 32; i++) {
dev->page[i].valid = 1;
dev->page[i].regs_2x8 = 0xff;
dev->page[i].regs_2x9 = 0x03;
dev->page[i].scat = dev;
mem_mapping_add(&dev->ems_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000,
mem_read_scatb, mem_read_scatw, mem_read_scatl,
mem_write_scatb, mem_write_scatw, mem_write_scatl,
ram + ((i + (i >= 24 ? 28 : 16)) << 14),
0, &dev->page[i]);
}
for (i = (dev->regs[SCAT_VERSION] < 4 ? 0 : 8); i < 16; i++) {
mem_mapping_add(&dev->high_mapping[i], (i << 14) + 0xfc0000, 0x04000,
mem_read_bios, mem_read_biosw, mem_read_biosl,
mem_write_null, mem_write_nullw, mem_write_nulll,
rom + ((i << 14) & biosmask), 0, NULL);
mem_mapping_enable(&dev->high_mapping[i]);
}
}
for (i = 0; i < 6; i++) {
mem_mapping_add(&dev->remap_mapping[i], 0x100000 + (i << 16), 0x10000,
mem_read_scatb, mem_read_scatw, mem_read_scatl,
mem_write_scatb, mem_write_scatw, mem_write_scatl,
mem_size >= 1024 ? ram + get_addr(dev, 0x100000 + (i << 16), NULL) : NULL,
MEM_MAPPING_INTERNAL, &dev->null_page);
}
if (sx) {
dev->external_is_RAS = scatsx_external_is_RAS[mem_size >> 9];
} else {
dev->external_is_RAS = (dev->regs[SCAT_VERSION] > 3) || (((mem_size & ~2047) >> 11) + ((mem_size & 1536) >> 9) + ((mem_size & 511) >> 7)) > 4;
}
set_xms_bound(dev, 0);
memmap_state_update(dev);
shadow_state_update(dev);
io_sethandler(0x0022, 2,
scat_in, NULL, NULL, scat_out, NULL, NULL, dev);
device_add(&port_92_device);
return(dev);
}
const device_t scat_device = {
"C&T SCAT (v1)",
0,
0,
scat_init, scat_close, NULL,
NULL, NULL, NULL,
NULL
};
const device_t scat_4_device = {
"C&T SCAT (v4)",
0,
4,
scat_init, scat_close, NULL,
NULL, NULL, NULL,
NULL
};
const device_t scat_sx_device = {
"C&T SCATsx",
0,
32,
scat_init, scat_close, NULL,
NULL, NULL, NULL,
NULL
};