2017-09-25 04:31:20 -04:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* Version: @(#)at_scat.c 1.0.2 2017/09/24
|
|
|
|
|
*
|
|
|
|
|
* Authors: Original by GreatPsycho for PCem.
|
|
|
|
|
* Fred N. van Kempen, <decwiz@yahoo.com>
|
|
|
|
|
* Copyright 2017 Fred N. van Kempen.
|
|
|
|
|
*/
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <wchar.h>
|
2017-09-02 20:39:57 +02:00
|
|
|
#include "../ibm.h"
|
|
|
|
|
#include "../cpu/cpu.h"
|
2017-09-04 01:52:29 -04:00
|
|
|
#include "../cpu/x86.h"
|
2017-09-02 20:39:57 +02:00
|
|
|
#include "../io.h"
|
|
|
|
|
#include "../mem.h"
|
|
|
|
|
#include "machine_at.h"
|
|
|
|
|
#include "machine_at_scat.h"
|
|
|
|
|
|
2017-09-04 01:52:29 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
#define SCAT_DEBUG 2
|
|
|
|
|
|
|
|
|
|
#define SCAT_DMA_WS_CTL 0x01
|
|
|
|
|
#define SCAT_VERSION 0x40
|
|
|
|
|
#define SCAT_CLOCK_CTL 0x41
|
|
|
|
|
#define SCAT_PERIPH_CTL 0x44
|
|
|
|
|
#define SCAT_MISC_STATUS 0x45
|
|
|
|
|
#define SCAT_POWER_MGMT 0x46
|
|
|
|
|
#define SCAT_ROM_ENABLE 0x48
|
|
|
|
|
#define SCAT_RAM_WR_PROTECT 0x49
|
|
|
|
|
#define SCAT_SHADOW_RAM_EN_1 0x4a
|
|
|
|
|
#define SCAT_SHADOW_RAM_EN_2 0x4b
|
|
|
|
|
#define SCAT_SHADOW_RAM_EN_3 0x4c
|
|
|
|
|
#define SCAT_DRAM_CONFIG 0x4d
|
|
|
|
|
#define SCAT_EXT_BOUNDARY 0x4e
|
|
|
|
|
#define SCAT_EMS_CTL 0x4f
|
|
|
|
|
#define SCAT_SYS_CTL 0x7f /* port 92 */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint8_t regs_2x8;
|
|
|
|
|
uint8_t regs_2x9;
|
|
|
|
|
} ems_t;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t scat_regs[128];
|
|
|
|
|
static int scat_index;
|
|
|
|
|
static uint32_t scat_xms_bound;
|
|
|
|
|
static uint8_t scat_ems_reg = 0;
|
|
|
|
|
static ems_t scat_ems[32]; /* EMS page regs */
|
|
|
|
|
static mem_mapping_t scat_mapping[32]; /* EMS pages */
|
|
|
|
|
static mem_mapping_t scat_top_mapping[24]; /* top 384K mapping */
|
|
|
|
|
static mem_mapping_t scat_A000_mapping; /* A000-C000 mapping */
|
|
|
|
|
static mem_mapping_t scat_shadowram_mapping[6]; /* BIOS shadowing */
|
|
|
|
|
static mem_mapping_t scat_high_mapping[16]; /* >1M mapping */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
shadow_state_update(void)
|
2017-09-02 20:39:57 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
int i, val;
|
|
|
|
|
|
|
|
|
|
/* TODO - ROMCS enable features should be implemented later. */
|
|
|
|
|
for (i=0; i<24; i++) {
|
|
|
|
|
val = ((scat_regs[SCAT_SHADOW_RAM_EN_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL;
|
|
|
|
|
if (i < 8) {
|
|
|
|
|
val |= ((scat_regs[SCAT_SHADOW_RAM_EN_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL;
|
|
|
|
|
} else {
|
|
|
|
|
if ((scat_regs[SCAT_RAM_WR_PROTECT] >> ((i - 8) >> 1)) & 1)
|
|
|
|
|
val |= MEM_WRITE_DISABLED;
|
|
|
|
|
else
|
|
|
|
|
val |= ((scat_regs[SCAT_SHADOW_RAM_EN_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL;
|
|
|
|
|
}
|
|
|
|
|
mem_set_mem_state((i + 40) << 14, 0x4000, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flushmmucache();
|
|
|
|
|
}
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
static void
|
|
|
|
|
set_xms_bound(uint8_t val)
|
|
|
|
|
{
|
|
|
|
|
uint32_t max_xms, max_mem;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
max_mem = (mem_size << 10);
|
|
|
|
|
max_xms = (mem_size >= 16384) ? 0xFC0000 : max_mem;
|
|
|
|
|
pclog("SCAT: set_xms_bound(%02x): max_mem=%d, max_xms=%d\n",
|
|
|
|
|
val, max_mem, max_xms);
|
|
|
|
|
|
|
|
|
|
switch (val & 0x0f) {
|
|
|
|
|
case 1:
|
|
|
|
|
scat_xms_bound = 0x100000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
scat_xms_bound = 0x140000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
scat_xms_bound = 0x180000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
|
scat_xms_bound = 0x200000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 5:
|
|
|
|
|
scat_xms_bound = 0x300000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 6:
|
|
|
|
|
scat_xms_bound = 0x400000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 7:
|
|
|
|
|
scat_xms_bound = 0x600000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 8:
|
|
|
|
|
scat_xms_bound = 0x800000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 9:
|
|
|
|
|
scat_xms_bound = 0xA00000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 10:
|
|
|
|
|
scat_xms_bound = 0xC00000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 11:
|
|
|
|
|
scat_xms_bound = 0xE00000;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
scat_xms_bound = max_xms;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((val & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIG] & 0x0f) == 3) {
|
|
|
|
|
if (val != 1) {
|
|
|
|
|
if (mem_size > 1024)
|
|
|
|
|
mem_mapping_disable(&ram_high_mapping);
|
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
|
mem_mapping_enable(&scat_shadowram_mapping[i]);
|
|
|
|
|
if ((val & 0x0f) == 0)
|
|
|
|
|
scat_xms_bound = 0x160000;
|
|
|
|
|
} else {
|
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
|
mem_mapping_disable(&scat_shadowram_mapping[i]);
|
|
|
|
|
if (mem_size > 1024)
|
|
|
|
|
mem_mapping_enable(&ram_high_mapping);
|
|
|
|
|
}
|
|
|
|
|
pclog("SCAT: set XMS bound(%02X) = %06X (%dK for EMS)\n",
|
|
|
|
|
val, scat_xms_bound, (0x160000-scat_xms_bound)>>10);
|
|
|
|
|
|
|
|
|
|
if (scat_xms_bound > 0x100000)
|
|
|
|
|
mem_set_mem_state(0x100000,
|
|
|
|
|
scat_xms_bound - 0x100000,
|
|
|
|
|
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
|
|
|
|
if (scat_xms_bound < 0x160000)
|
|
|
|
|
mem_set_mem_state(scat_xms_bound,
|
|
|
|
|
0x160000 - scat_xms_bound,
|
|
|
|
|
MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
|
|
|
|
|
} else {
|
|
|
|
|
#if 0
|
|
|
|
|
for (i=0; i<6; i++)
|
|
|
|
|
mem_mapping_disable(&scat_shadowram_mapping[i]);
|
|
|
|
|
if (mem_size > 1024)
|
|
|
|
|
mem_mapping_enable(&ram_high_mapping);
|
|
|
|
|
#endif
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
if (scat_xms_bound > max_xms)
|
|
|
|
|
scat_xms_bound = max_xms;
|
|
|
|
|
pclog("SCAT: set XMS bound(%02X) = %06X (%dK for EMS)\n",
|
|
|
|
|
val, scat_xms_bound, (max_mem-scat_xms_bound)>>10);
|
|
|
|
|
|
|
|
|
|
if (scat_xms_bound > 0x100000)
|
|
|
|
|
mem_set_mem_state(0x100000,
|
|
|
|
|
scat_xms_bound-0x100000,
|
|
|
|
|
MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
|
|
|
|
if (scat_xms_bound < max_mem)
|
|
|
|
|
mem_set_mem_state(scat_xms_bound,
|
|
|
|
|
(mem_size<<10)-scat_xms_bound,
|
|
|
|
|
MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-16 16:00:44 -04:00
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
static uint32_t
|
|
|
|
|
get_addr(uint32_t addr, ems_t *p)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
if (p && (scat_regs[SCAT_EMS_CTL] & 0x80) && (p->regs_2x9 & 0x80)) {
|
|
|
|
|
addr = (addr & 0x3fff) | (((p->regs_2x9 & 3)<<8) | p->regs_2x8)<<14;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mem_size < 2048 &&
|
|
|
|
|
((scat_regs[SCAT_DRAM_CONFIG] & 0x0F) > 7 ||
|
|
|
|
|
(scat_regs[SCAT_EXT_BOUNDARY] & 0x40) != 0))
|
|
|
|
|
addr = (addr & ~0x780000) | ((addr & 0x600000) >> 2);
|
|
|
|
|
else
|
|
|
|
|
if ((scat_regs[SCAT_DRAM_CONFIG] & 0x0F) < 8 &&
|
|
|
|
|
(scat_regs[SCAT_EXT_BOUNDARY] & 0x40) == 0) {
|
|
|
|
|
addr &= ~0x600000;
|
|
|
|
|
if (mem_size > 2048 || (mem_size == 2048 &&
|
|
|
|
|
(scat_regs[SCAT_DRAM_CONFIG] & 0x0F) < 6))
|
|
|
|
|
addr |= (addr & 0x180000) << 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((scat_regs[SCAT_EXT_BOUNDARY] & 0x40) == 0 &&
|
|
|
|
|
(scat_regs[SCAT_DRAM_CONFIG] & 0x0F) == 3 &&
|
|
|
|
|
(addr & ~0x600000) >= 0x100000 && (addr & ~0x600000) < 0x160000)
|
|
|
|
|
addr ^= mem_size < 2048 ? 0x1F0000 : 0x670000;
|
|
|
|
|
|
|
|
|
|
return(addr);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
static void
|
|
|
|
|
memmap_state_update(void)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
uint32_t addr;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=16; i<24; i++) {
|
|
|
|
|
addr = get_addr(0x40000 + (i<<14), NULL);
|
|
|
|
|
mem_mapping_set_exec(&scat_top_mapping[i],
|
|
|
|
|
addr < (mem_size<<10) ? ram+addr : NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addr = get_addr(0xA0000, NULL);
|
|
|
|
|
mem_mapping_set_exec(&scat_A000_mapping,
|
|
|
|
|
addr < (mem_size<<10) ? ram+addr : NULL);
|
|
|
|
|
|
|
|
|
|
for (i=0; i<6; i++) {
|
|
|
|
|
addr = get_addr(0x100000 + (i<<16), NULL);
|
|
|
|
|
mem_mapping_set_exec(&scat_shadowram_mapping[i],
|
|
|
|
|
addr < (mem_size<<10) ? ram+addr : NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flushmmucache();
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
static void
|
|
|
|
|
ems_state(int state)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
uint32_t base_addr, virt_addr;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0; i<32; i++) {
|
|
|
|
|
base_addr = (i + 16) << 14;
|
|
|
|
|
|
|
|
|
|
if (i >= 24)
|
|
|
|
|
base_addr += 0x30000;
|
|
|
|
|
|
|
|
|
|
if (state && (scat_ems[i].regs_2x9 & 0x80)) {
|
|
|
|
|
virt_addr = get_addr(base_addr, &scat_ems[i]);
|
|
|
|
|
if (i < 24)
|
|
|
|
|
mem_mapping_disable(&scat_top_mapping[i]);
|
|
|
|
|
mem_mapping_enable(&scat_mapping[i]);
|
|
|
|
|
if (virt_addr < (mem_size<<10))
|
|
|
|
|
mem_mapping_set_exec(&scat_mapping[i], ram+virt_addr);
|
|
|
|
|
else
|
|
|
|
|
mem_mapping_set_exec(&scat_mapping[i], NULL);
|
|
|
|
|
} else {
|
|
|
|
|
mem_mapping_set_exec(&scat_mapping[i], ram+base_addr);
|
|
|
|
|
mem_mapping_disable(&scat_mapping[i]);
|
|
|
|
|
#if 0
|
|
|
|
|
if (i < 24)
|
|
|
|
|
mem_mapping_enable(&scat_top_mapping[i]);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
/* Read a byte from a LIM/EMS page. */
|
|
|
|
|
static uint8_t
|
|
|
|
|
ems_pgrd(uint32_t vaddr, void *priv)
|
2017-08-19 17:51:58 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
ems_t *ems = (ems_t *)priv;
|
|
|
|
|
uint32_t addr;
|
|
|
|
|
uint8_t val = 0xff;
|
|
|
|
|
|
|
|
|
|
addr = get_addr(vaddr, ems);
|
|
|
|
|
if (addr < (mem_size << 10))
|
|
|
|
|
val = mem_read_ram(addr, priv);
|
|
|
|
|
#if SCAT_DEBUG > 1
|
|
|
|
|
pclog("SCAT: ems_pgrd(%06x->%06x) = %02x\n", vaddr, addr, val);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return(val);
|
2017-08-19 17:51:58 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
/* Write a byte to a LIM/EMS page. */
|
|
|
|
|
static void
|
|
|
|
|
ems_pgwr(uint32_t vaddr, uint8_t val, void *priv)
|
2017-07-15 14:01:19 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
ems_t *ems = (ems_t *)priv;
|
|
|
|
|
uint32_t addr;
|
|
|
|
|
|
|
|
|
|
addr = get_addr(vaddr, ems);
|
|
|
|
|
#if SCAT_DEBUG > 1
|
|
|
|
|
pclog("SCAT: ems_pgwr(%06x->%06x, %02x)\n", vaddr, addr, val);
|
|
|
|
|
#endif
|
|
|
|
|
if (addr < (mem_size << 10))
|
|
|
|
|
mem_write_ram(addr, val, priv);
|
2017-07-15 14:01:19 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
/* Read from a LIM/EMS control register. */
|
|
|
|
|
static uint8_t
|
|
|
|
|
ems_read(uint16_t port, void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
uint8_t val = 0xff;
|
|
|
|
|
uint8_t idx;
|
|
|
|
|
|
|
|
|
|
switch (port) {
|
|
|
|
|
case 0x208:
|
|
|
|
|
case 0x218:
|
|
|
|
|
if ((scat_regs[SCAT_EMS_CTL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
|
|
|
|
|
idx = scat_ems_reg & 0x1f;
|
|
|
|
|
val = scat_ems[idx].regs_2x8;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x209:
|
|
|
|
|
case 0x219:
|
|
|
|
|
if ((scat_regs[SCAT_EMS_CTL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
|
|
|
|
|
idx = scat_ems_reg & 0x1f;
|
|
|
|
|
val = scat_ems[idx].regs_2x9;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x20A:
|
|
|
|
|
case 0x21A:
|
|
|
|
|
if ((scat_regs[SCAT_EMS_CTL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
|
|
|
|
|
val = scat_ems_reg;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if SCAT_DEBUG > 2
|
|
|
|
|
pclog("SCAT: ems_read(%04x) = %02x\n", port, val);
|
2017-08-14 19:43:08 +02:00
|
|
|
#endif
|
2017-09-25 04:31:20 -04:00
|
|
|
return(val);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
/* Write to one of the LIM/EMS control registers. */
|
|
|
|
|
static void
|
|
|
|
|
ems_write(uint16_t port, uint8_t val, void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
uint32_t base_addr, virt_addr;
|
|
|
|
|
uint8_t idx;
|
|
|
|
|
|
|
|
|
|
#if SCAT_DEBUG > 1
|
|
|
|
|
pclog("SCAT: ems_write(%04x, %02x)\n", port, val);
|
|
|
|
|
#endif
|
|
|
|
|
switch(port) {
|
|
|
|
|
case 0x208:
|
|
|
|
|
case 0x218:
|
|
|
|
|
if ((scat_regs[SCAT_EMS_CTL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
|
|
|
|
|
idx = scat_ems_reg & 0x1f;
|
|
|
|
|
scat_ems[idx].regs_2x8 = val;
|
|
|
|
|
base_addr = (idx + 16) << 14;
|
|
|
|
|
if (idx >= 24)
|
|
|
|
|
base_addr += 0x30000;
|
|
|
|
|
|
|
|
|
|
if ((scat_regs[SCAT_EMS_CTL] & 0x80) && (scat_ems[idx].regs_2x9 & 0x80)) {
|
|
|
|
|
virt_addr = get_addr(base_addr, &scat_ems[idx]);
|
|
|
|
|
if (virt_addr < (mem_size << 10))
|
|
|
|
|
mem_mapping_set_exec(&scat_mapping[idx], ram + virt_addr);
|
|
|
|
|
else
|
|
|
|
|
mem_mapping_set_exec(&scat_mapping[idx], NULL);
|
|
|
|
|
flushmmucache();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x209:
|
|
|
|
|
case 0x219:
|
|
|
|
|
if ((scat_regs[SCAT_EMS_CTL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
|
|
|
|
|
idx = scat_ems_reg & 0x1f;
|
|
|
|
|
scat_ems[idx].regs_2x9 = val;
|
|
|
|
|
base_addr = (idx + 16) << 14;
|
|
|
|
|
if (idx >= 24)
|
|
|
|
|
base_addr += 0x30000;
|
|
|
|
|
|
|
|
|
|
if (scat_regs[SCAT_EMS_CTL] & 0x80) {
|
|
|
|
|
if (val & 0x80) {
|
|
|
|
|
virt_addr = get_addr(base_addr, &scat_ems[idx]);
|
|
|
|
|
if (idx < 24)
|
|
|
|
|
mem_mapping_disable(&scat_top_mapping[idx]);
|
|
|
|
|
if (virt_addr < (mem_size << 10))
|
|
|
|
|
mem_mapping_set_exec(&scat_mapping[idx], ram+virt_addr);
|
|
|
|
|
else
|
|
|
|
|
mem_mapping_set_exec(&scat_mapping[idx], NULL);
|
|
|
|
|
mem_mapping_enable(&scat_mapping[idx]);
|
|
|
|
|
} else {
|
|
|
|
|
mem_mapping_set_exec(&scat_mapping[idx], ram + base_addr);
|
|
|
|
|
mem_mapping_disable(&scat_mapping[idx]);
|
|
|
|
|
if (idx < 24)
|
|
|
|
|
mem_mapping_enable(&scat_top_mapping[idx]);
|
|
|
|
|
}
|
|
|
|
|
flushmmucache();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (scat_ems_reg & 0x80) {
|
|
|
|
|
scat_ems_reg = (scat_ems_reg & 0xe0) | ((scat_ems_reg + 1) & 0x1f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x20A:
|
|
|
|
|
case 0x21A:
|
|
|
|
|
if ((scat_regs[SCAT_EMS_CTL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) {
|
|
|
|
|
scat_ems_reg = val;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
static uint8_t
|
|
|
|
|
scat_read(uint16_t port, void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
uint8_t val = 0xff;
|
|
|
|
|
|
|
|
|
|
switch (port) {
|
|
|
|
|
case 0x23:
|
|
|
|
|
switch (scat_index) {
|
|
|
|
|
case SCAT_MISC_STATUS:
|
|
|
|
|
val = (scat_regs[scat_index] & 0xbf) | ((mem_a20_key & 2) << 5);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SCAT_DRAM_CONFIG:
|
|
|
|
|
val = (scat_regs[scat_index] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10);
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
default:
|
|
|
|
|
val = scat_regs[scat_index];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
case 0x92:
|
|
|
|
|
val = scat_regs[SCAT_SYS_CTL];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if SCAT_DEBUG > 2
|
|
|
|
|
pclog("SCAT: read(%04x) = %02x\n", port, val);
|
|
|
|
|
#endif
|
|
|
|
|
return(val);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2017-06-16 16:00:44 -04:00
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
/* Write to one of the Internal Control Registers. */
|
|
|
|
|
static void
|
|
|
|
|
ics_write(uint8_t idx, uint8_t val)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
uint8_t reg_valid = 0;
|
|
|
|
|
uint8_t shadow_update = 0;
|
|
|
|
|
uint8_t map_update = 0;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
#if SCAT_DEBUG > 1
|
|
|
|
|
pclog("SCAT: icr_write(%02x, %02x)\n", idx, val);
|
|
|
|
|
#endif
|
|
|
|
|
switch (idx) {
|
|
|
|
|
case SCAT_CLOCK_CTL:
|
|
|
|
|
case SCAT_PERIPH_CTL:
|
|
|
|
|
reg_valid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SCAT_EMS_CTL:
|
|
|
|
|
pclog("SCAT: EMSctrl(%02x)\n", val);
|
|
|
|
|
if (val & 0x40) {
|
|
|
|
|
if (val & 1) {
|
|
|
|
|
io_sethandler(0x0218, 3,
|
|
|
|
|
ems_read, NULL, NULL,
|
|
|
|
|
ems_write, NULL, NULL, NULL);
|
|
|
|
|
io_removehandler(0x0208, 3,
|
|
|
|
|
ems_read, NULL, NULL,
|
|
|
|
|
ems_write, NULL, NULL, NULL);
|
|
|
|
|
} else {
|
|
|
|
|
io_sethandler(0x0208, 3,
|
|
|
|
|
ems_read, NULL, NULL,
|
|
|
|
|
ems_write, NULL, NULL, NULL);
|
|
|
|
|
io_removehandler(0x0218, 3,
|
|
|
|
|
ems_read, NULL, NULL,
|
|
|
|
|
ems_write, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
io_removehandler(0x0208, 3,
|
|
|
|
|
ems_read, NULL, NULL,
|
|
|
|
|
ems_write, NULL, NULL, NULL);
|
|
|
|
|
io_removehandler(0x0218, 3,
|
|
|
|
|
ems_read, NULL, NULL,
|
|
|
|
|
ems_write, NULL, NULL, NULL);
|
|
|
|
|
}
|
|
|
|
|
ems_state(val & 0x80);
|
|
|
|
|
reg_valid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SCAT_POWER_MGMT:
|
|
|
|
|
val &= 0x40;
|
|
|
|
|
reg_valid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SCAT_DRAM_CONFIG:
|
|
|
|
|
if ((scat_regs[SCAT_EXT_BOUNDARY] & 0x40) == 0) {
|
|
|
|
|
pclog("SCAT: 0\n");
|
|
|
|
|
if ((val & 0x0f) == 3) {
|
|
|
|
|
pclog("SCAT: 3\n");
|
|
|
|
|
if (mem_size > 1024)
|
|
|
|
|
mem_mapping_disable(&ram_high_mapping);
|
|
|
|
|
for (idx=0; idx<6; idx++)
|
|
|
|
|
mem_mapping_enable(&scat_shadowram_mapping[idx]);
|
|
|
|
|
} else {
|
|
|
|
|
pclog("SCAT: 0\n");
|
|
|
|
|
for (idx=0; idx<6; idx++)
|
|
|
|
|
mem_mapping_disable(&scat_shadowram_mapping[idx]);
|
|
|
|
|
#if 0
|
|
|
|
|
if (mem_size > 1024)
|
|
|
|
|
mem_mapping_enable(&ram_high_mapping);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
pclog("SCAT: 1\n");
|
|
|
|
|
for (idx=0; idx<6; idx++)
|
|
|
|
|
mem_mapping_disable(&scat_shadowram_mapping[idx]);
|
|
|
|
|
if (mem_size > 1024)
|
|
|
|
|
mem_mapping_enable(&ram_high_mapping);
|
|
|
|
|
}
|
|
|
|
|
map_update = 1;
|
|
|
|
|
|
|
|
|
|
cpu_waitstates = (val & 0x70) == 0 ? 1 : 2;
|
|
|
|
|
cpu_update_waitstates();
|
|
|
|
|
|
|
|
|
|
reg_valid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SCAT_EXT_BOUNDARY:
|
|
|
|
|
set_xms_bound(val & 0x4f);
|
|
|
|
|
mem_set_mem_state(0x40000, 0x60000,
|
|
|
|
|
(val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
|
|
|
|
if ((val ^ scat_regs[SCAT_EXT_BOUNDARY]) & 0x40)
|
|
|
|
|
map_update = 1;
|
|
|
|
|
reg_valid = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SCAT_ROM_ENABLE:
|
|
|
|
|
case SCAT_RAM_WR_PROTECT:
|
|
|
|
|
case SCAT_SHADOW_RAM_EN_1:
|
|
|
|
|
case SCAT_SHADOW_RAM_EN_2:
|
|
|
|
|
case SCAT_SHADOW_RAM_EN_3:
|
|
|
|
|
reg_valid = 1;
|
|
|
|
|
shadow_update = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (reg_valid)
|
|
|
|
|
scat_regs[scat_index] = val;
|
|
|
|
|
#ifndef RELEASE_BUILD
|
|
|
|
|
else
|
|
|
|
|
pclog("SCAT: attemped write to register %02X at %04X:%04X\n",
|
|
|
|
|
idx, val, CS, cpu_state.pc);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (shadow_update)
|
|
|
|
|
shadow_state_update();
|
|
|
|
|
|
|
|
|
|
if (map_update)
|
|
|
|
|
memmap_state_update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
scat_write(uint16_t port, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
#if SCAT_DEBUG > 2
|
|
|
|
|
pclog("SCAT: write(%04x, %02x)\n", port, val);
|
|
|
|
|
#endif
|
|
|
|
|
switch (port) {
|
|
|
|
|
case 0x22:
|
|
|
|
|
scat_index = val;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x23:
|
|
|
|
|
ics_write(scat_index, val);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x92:
|
|
|
|
|
if ((mem_a20_alt ^ val) & 2) {
|
|
|
|
|
mem_a20_alt = val & 2;
|
|
|
|
|
mem_a20_recalc();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((~scat_regs[SCAT_SYS_CTL] & val) & 1) {
|
|
|
|
|
softresetx86();
|
|
|
|
|
cpu_set_edx();
|
|
|
|
|
}
|
|
|
|
|
scat_regs[SCAT_SYS_CTL] = val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2017-06-16 16:00:44 -04:00
|
|
|
|
2017-08-24 01:14:39 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
static void
|
|
|
|
|
scat_init(void)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
#if SCAT_DEBUG
|
|
|
|
|
pclog("SCAT: initializing..\n");
|
|
|
|
|
#endif
|
|
|
|
|
io_sethandler(0x0022, 2,
|
|
|
|
|
scat_read, NULL, NULL, scat_write, NULL, NULL, NULL);
|
|
|
|
|
io_sethandler(0x0092, 1,
|
|
|
|
|
scat_read, NULL, NULL, scat_write, NULL, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
for (i=0; i<128; i++)
|
|
|
|
|
scat_regs[i] = 0xff;
|
|
|
|
|
scat_regs[SCAT_DMA_WS_CTL] = 0x00;
|
|
|
|
|
scat_regs[SCAT_VERSION] = 0x0a;
|
|
|
|
|
scat_regs[SCAT_CLOCK_CTL] = 0x02;
|
|
|
|
|
scat_regs[SCAT_PERIPH_CTL] = 0x80;
|
|
|
|
|
scat_regs[SCAT_MISC_STATUS] = 0x37;
|
|
|
|
|
scat_regs[SCAT_POWER_MGMT] = 0x00;
|
|
|
|
|
scat_regs[SCAT_ROM_ENABLE] = 0xC0;
|
|
|
|
|
scat_regs[SCAT_RAM_WR_PROTECT] = 0x00;
|
|
|
|
|
scat_regs[SCAT_SHADOW_RAM_EN_1] = 0x00;
|
|
|
|
|
scat_regs[SCAT_SHADOW_RAM_EN_2] = 0x00;
|
|
|
|
|
scat_regs[SCAT_SHADOW_RAM_EN_3] = 0x00;
|
|
|
|
|
scat_regs[SCAT_DRAM_CONFIG] = cpu_waitstates == 1 ? 0x00 : 0x10;
|
|
|
|
|
scat_regs[SCAT_EXT_BOUNDARY] = 0x00;
|
|
|
|
|
scat_regs[SCAT_EMS_CTL] = 0x00;
|
|
|
|
|
scat_regs[SCAT_SYS_CTL] = 0x00;
|
|
|
|
|
|
|
|
|
|
/* Limit RAM size to 16MB. */
|
|
|
|
|
mem_mapping_set_addr(&ram_low_mapping, 0x000000, 0x40000);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Configure the DRAM controller.
|
|
|
|
|
*
|
|
|
|
|
* Since SCAT allows mixing of the various-sized DRAM chips,
|
|
|
|
|
* memory configuration is not simple. The SCAT datasheet
|
|
|
|
|
* tells us in table 6-6 how to set up the four banks:
|
|
|
|
|
*
|
|
|
|
|
* MEM SIZE MIX_EN RAMCFG Ext RAM Comments
|
|
|
|
|
* 0 K 0 0x00 No RAM installed
|
|
|
|
|
* 512 K 0 0x01 0 K
|
|
|
|
|
* 640 K 0 0x02 0 K
|
|
|
|
|
* 1 M 0 0x03 384K
|
|
|
|
|
* 1 M 0 0x04 0 K
|
|
|
|
|
* 1.5 M 0 0x05 512K
|
|
|
|
|
* 2 M 0 0x06 1 M 4x512K
|
|
|
|
|
* 2 M 0 0x08 1 M 1x2M
|
|
|
|
|
* 2.5 M 1 0x01 1.5M 2M+512K
|
|
|
|
|
* 3 M 1 0x04 2 M 1x2M
|
|
|
|
|
* 4 M 0 0x09 3 M 2x2M
|
|
|
|
|
* 4.5 M 1 0x02 3.5M 2x2M+512K
|
|
|
|
|
* 5 M 1 0x05 4 M 2x2M+2x512K
|
|
|
|
|
* 6 M 0 0x0a 5 M 3x2M
|
|
|
|
|
* 6.5 M 1 0x03 5.5M 3x2M+512K
|
|
|
|
|
* 8 M 0 0x0b 7 M 4x2M
|
|
|
|
|
*/
|
|
|
|
|
pclog("SCAT: mem_size=%d\n", mem_size);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* Create the 32 EMS page frame mappings for 256-640K. */
|
|
|
|
|
for (i=0; i<24; i++) {
|
|
|
|
|
mem_mapping_add(&scat_top_mapping[i],
|
|
|
|
|
0x40000 + (i<<14), 0x4000,
|
|
|
|
|
ems_pgrd, NULL, NULL,
|
|
|
|
|
ems_pgwr, NULL, NULL,
|
|
|
|
|
mem_size > 256+(i<<4) ? ram+0x40000+(i<<14) : NULL,
|
|
|
|
|
MEM_MAPPING_INTERNAL, NULL);
|
|
|
|
|
// mem_mapping_enable(&scat_top_mapping[i]);
|
|
|
|
|
mem_mapping_disable(&scat_top_mapping[i]);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* Re-map the 128K at A0000 (video BIOS) to above 16MB+top. */
|
|
|
|
|
mem_mapping_add(&scat_A000_mapping,
|
|
|
|
|
0xA0000, 0x20000,
|
|
|
|
|
ems_pgrd, NULL, NULL,
|
|
|
|
|
ems_pgwr, NULL, NULL,
|
|
|
|
|
ram+0xA0000,
|
|
|
|
|
MEM_MAPPING_INTERNAL, NULL);
|
|
|
|
|
mem_mapping_disable(&scat_A000_mapping);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* Create 32 page frames for EMS, each 16K. */
|
|
|
|
|
for (i=0; i<32; i++) {
|
|
|
|
|
scat_ems[i].regs_2x8 = 0xff;
|
|
|
|
|
scat_ems[i].regs_2x9 = 0x03;
|
|
|
|
|
mem_mapping_add(&scat_mapping[i],
|
|
|
|
|
(i + (i >= 24 ? 28 : 16)) << 14, 0x04000,
|
|
|
|
|
ems_pgrd, NULL, NULL,
|
|
|
|
|
ems_pgwr, NULL, NULL,
|
|
|
|
|
ram + ((i + (i >= 24 ? 28 : 16)) << 14),
|
|
|
|
|
0, &scat_ems[i]);
|
|
|
|
|
mem_mapping_disable(&scat_mapping[i]);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// for (i=4; i<10; i++) isram[i] = 0;
|
|
|
|
|
|
|
|
|
|
/* Re-map the BIOS ROM (C0000-FFFFF) area. */
|
|
|
|
|
for (i=12; i<16; i++) {
|
|
|
|
|
mem_mapping_add(&scat_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),
|
|
|
|
|
0, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
for (i=0; i<6; i++) {
|
|
|
|
|
mem_mapping_add(&scat_shadowram_mapping[i],
|
|
|
|
|
0x100000 + (i<<16), 0x10000,
|
|
|
|
|
ems_pgrd, NULL, NULL,
|
|
|
|
|
ems_pgwr, NULL, NULL,
|
|
|
|
|
mem_size >= 1024 ? ram+get_addr(0x100000+(i<<16), NULL) : NULL,
|
|
|
|
|
MEM_MAPPING_INTERNAL, NULL);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
set_xms_bound(0);
|
|
|
|
|
shadow_state_update();
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
2017-09-02 20:39:57 +02:00
|
|
|
|
|
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
void
|
|
|
|
|
machine_at_scat_init(void)
|
2017-09-02 20:39:57 +02:00
|
|
|
{
|
2017-09-25 04:31:20 -04:00
|
|
|
machine_at_init();
|
2017-09-18 22:38:15 -04:00
|
|
|
|
2017-09-25 04:31:20 -04:00
|
|
|
scat_init();
|
2017-09-02 20:39:57 +02:00
|
|
|
}
|