The missing chipset/compaq_386.c.
This commit is contained in:
767
src/chipset/compaq_386.c
Normal file
767
src/chipset/compaq_386.c
Normal file
@@ -0,0 +1,767 @@
|
||||
/*
|
||||
* 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 the Compaq 386 memory controller.
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
* Copyright 2023 Miran Grca.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <math.h>
|
||||
#include <86box/86box.h>
|
||||
#include "cpu.h"
|
||||
#include <86box/io.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/pit.h>
|
||||
#include <86box/mem.h>
|
||||
#include <86box/rom.h>
|
||||
#include <86box/device.h>
|
||||
#include <86box/keyboard.h>
|
||||
#include <86box/fdd.h>
|
||||
#include <86box/fdc.h>
|
||||
#include <86box/fdc_ext.h>
|
||||
#include <86box/hdc.h>
|
||||
#include <86box/hdc_ide.h>
|
||||
#include <86box/machine.h>
|
||||
#include <86box/video.h>
|
||||
#include <86box/vid_cga.h>
|
||||
#include <86box/vid_cga_comp.h>
|
||||
#include <86box/plat_unused.h>
|
||||
|
||||
#define RAM_DIAG_L_BASE_MEM_640KB 0x00
|
||||
#define RAM_DIAG_L_BASE_MEM_INV 0x10
|
||||
#define RAM_DIAG_L_BASE_MEM_512KB 0x20
|
||||
#define RAM_DIAG_L_BASE_MEM_256KB 0x30
|
||||
#define RAM_DIAG_L_BASE_MEM_MASK 0x30
|
||||
#define RAM_DIAG_L_PERMA_BITS 0x80
|
||||
|
||||
#define RAM_DIAG_H_SYS_RAM_4MB 0x01
|
||||
#define RAM_DIAG_H_SYS_RAM_1MB 0x02
|
||||
#define RAM_DIAG_H_SYS_RAM_NONE 0x03
|
||||
#define RAM_DIAG_H_SYS_RAM_MASK 0x03
|
||||
#define RAM_DIAG_H_MOD_A_RAM_4MB 0x04
|
||||
#define RAM_DIAG_H_MOD_A_RAM_1MB 0x08
|
||||
#define RAM_DIAG_H_MOD_A_RAM_NONE 0x0c
|
||||
#define RAM_DIAG_H_MOD_A_RAM_MASK 0x0c
|
||||
#define RAM_DIAG_H_MOD_B_RAM_4MB 0x10
|
||||
#define RAM_DIAG_H_MOD_B_RAM_1MB 0x20
|
||||
#define RAM_DIAG_H_MOD_B_RAM_NONE 0x30
|
||||
#define RAM_DIAG_H_MOD_B_RAM_MASK 0x30
|
||||
#define RAM_DIAG_H_MOD_C_RAM_4MB 0x40
|
||||
#define RAM_DIAG_H_MOD_C_RAM_1MB 0x80
|
||||
#define RAM_DIAG_H_MOD_C_RAM_NONE 0xc0
|
||||
#define RAM_DIAG_H_MOD_C_RAM_MASK 0xc0
|
||||
|
||||
#define MEM_STATE_BUS 0x00
|
||||
#define MEM_STATE_SYS 0x01
|
||||
#define MEM_STATE_SYS_RELOC 0x02
|
||||
#define MEM_STATE_MOD_A 0x04
|
||||
#define MEM_STATE_MOD_B 0x08
|
||||
#define MEM_STATE_MOD_C 0x10
|
||||
#define MEM_STATE_MASK (MEM_STATE_SYS | MEM_STATE_MOD_A | MEM_STATE_MOD_B | MEM_STATE_MOD_C)
|
||||
#define MEM_STATE_WP 0x20
|
||||
|
||||
typedef struct cpq_ram_t {
|
||||
uint8_t wp;
|
||||
|
||||
uint32_t phys_base;
|
||||
uint32_t virt_base;
|
||||
|
||||
mem_mapping_t mapping;
|
||||
} cpq_ram_t;
|
||||
|
||||
typedef struct cpq_386_t {
|
||||
uint8_t regs[8];
|
||||
|
||||
uint8_t old_state[256];
|
||||
uint8_t mem_state[256];
|
||||
|
||||
uint32_t ram_bases[4];
|
||||
|
||||
uint32_t ram_sizes[4];
|
||||
uint32_t ram_map_sizes[4];
|
||||
|
||||
cpq_ram_t ram[4][64];
|
||||
cpq_ram_t high_ram[16];
|
||||
|
||||
mem_mapping_t regs_mapping;
|
||||
} cpq_386_t;
|
||||
|
||||
static uint8_t
|
||||
cpq_read_ram(uint32_t addr, void *priv)
|
||||
{
|
||||
cpq_ram_t *dev = (cpq_ram_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
uint32_t old = addr;
|
||||
|
||||
addr = (addr - dev->virt_base) + dev->phys_base;
|
||||
|
||||
if (addr < (mem_size << 10))
|
||||
ret = mem_read_ram(addr, priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
cpq_read_ramw(uint32_t addr, void *priv)
|
||||
{
|
||||
cpq_ram_t *dev = (cpq_ram_t *) priv;
|
||||
uint16_t ret = 0xffff;
|
||||
uint32_t old = addr;
|
||||
|
||||
addr = (addr - dev->virt_base) + dev->phys_base;
|
||||
|
||||
if (addr < (mem_size << 10))
|
||||
ret = mem_read_ramw(addr, priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
cpq_read_raml(uint32_t addr, void *priv)
|
||||
{
|
||||
cpq_ram_t *dev = (cpq_ram_t *) priv;
|
||||
uint32_t ret = 0xffffffff;
|
||||
uint32_t old = addr;
|
||||
|
||||
addr = (addr - dev->virt_base) + dev->phys_base;
|
||||
|
||||
if (addr < (mem_size << 10))
|
||||
ret = mem_read_raml(addr, priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_write_ram(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
cpq_ram_t *dev = (cpq_ram_t *) priv;
|
||||
uint32_t old = addr;
|
||||
|
||||
addr = (addr - dev->virt_base) + dev->phys_base;
|
||||
|
||||
if (!dev->wp && (addr < (mem_size << 10)))
|
||||
mem_write_ram(addr, val, priv);
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_write_ramw(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
cpq_ram_t *dev = (cpq_ram_t *) priv;
|
||||
uint32_t old = addr;
|
||||
|
||||
addr = (addr - dev->virt_base) + dev->phys_base;
|
||||
|
||||
if (!dev->wp && (addr < (mem_size << 10)))
|
||||
mem_write_ramw(addr, val, priv);
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_write_raml(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
cpq_ram_t *dev = (cpq_ram_t *) priv;
|
||||
uint32_t old = addr;
|
||||
|
||||
addr = (addr - dev->virt_base) + dev->phys_base;
|
||||
|
||||
if (!dev->wp && (addr < (mem_size << 10)))
|
||||
mem_write_raml(addr, val, priv);
|
||||
}
|
||||
|
||||
static uint8_t
|
||||
cpq_read_regs(uint32_t addr, void *priv)
|
||||
{
|
||||
cpq_386_t *dev = (cpq_386_t *) priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
addr &= 0x00000fff;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00000000:
|
||||
case 0x00000001:
|
||||
/* RAM Diagnostics (Read Only) */
|
||||
case 0x00000002:
|
||||
case 0x00000003:
|
||||
/* RAM Setup Port (Read/Write) */
|
||||
ret = dev->regs[addr];
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
cpq_read_regsw(uint32_t addr, void *priv)
|
||||
{
|
||||
cpq_386_t *dev = (cpq_386_t *) priv;
|
||||
uint16_t ret = 0xffff;
|
||||
|
||||
ret = cpq_read_regs(addr, priv);
|
||||
ret |= (((uint16_t) cpq_read_regs(addr + 1, priv)) << 8);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
cpq_read_regsl(uint32_t addr, void *priv)
|
||||
{
|
||||
cpq_386_t *dev = (cpq_386_t *) priv;
|
||||
uint32_t ret = 0xffffffff;
|
||||
|
||||
ret = cpq_read_regsw(addr, priv);
|
||||
ret |= (((uint32_t) cpq_read_regsw(addr + 2, priv)) << 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_recalc_state(cpq_386_t *dev, uint8_t i)
|
||||
{
|
||||
uint32_t addr;
|
||||
|
||||
addr = ((uint32_t) i) << 16;
|
||||
if (dev->mem_state[i] == 0x00)
|
||||
mem_set_mem_state(addr, 0x00010000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
|
||||
else if (dev->mem_state[i] == MEM_STATE_WP)
|
||||
mem_set_mem_state(addr, 0x00010000, MEM_READ_EXTANY | MEM_WRITE_DISABLED);
|
||||
else if (dev->mem_state[i] & MEM_STATE_WP)
|
||||
mem_set_mem_state(addr, 0x00010000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED);
|
||||
else
|
||||
mem_set_mem_state(addr, 0x00010000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
||||
|
||||
dev->old_state[i] = dev->mem_state[i];
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_recalc_states(cpq_386_t *dev)
|
||||
{
|
||||
/* Recalculate the entire 16 MB space. */
|
||||
for (uint16_t i = 0; i < 256; i++) {
|
||||
if (dev->mem_state[i] != dev->old_state[i])
|
||||
cpq_recalc_state(dev, i);
|
||||
}
|
||||
|
||||
flushmmucache_nopc();
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_recalc_cache(cpq_386_t *dev)
|
||||
{
|
||||
cpu_cache_ext_enabled = (dev->regs[0x00000002] & 0x40);
|
||||
cpu_update_waitstates();
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_recalc_ram(cpq_386_t *dev)
|
||||
{
|
||||
uint8_t sys_ram = (dev->regs[0x00000001] & RAM_DIAG_H_SYS_RAM_MASK) & 0x01;
|
||||
uint8_t setup_port = dev->regs[0x00000002] & 0x0f;
|
||||
uint8_t sys_min_high = sys_ram ? 0xfa : 0xf4;
|
||||
uint8_t ram_states[4] = { MEM_STATE_SYS, MEM_STATE_MOD_A,
|
||||
MEM_STATE_MOD_B, MEM_STATE_MOD_C };
|
||||
uint8_t ram_bases[4][2][16] = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x10, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 } },
|
||||
{ { 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
|
||||
0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00 },
|
||||
{ 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 } },
|
||||
{ { 0x00, 0x00, 0x00, 0x20, 0x20, 0x00, 0x20, 0x20,
|
||||
0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 },
|
||||
{ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x50,
|
||||
0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 } },
|
||||
{ { 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x60,
|
||||
0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x00, 0x00 },
|
||||
{ 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
|
||||
0x00, 0x00, 0x90, 0x00, 0x00, 0xc0, 0xc0, 0xc0 } } };
|
||||
uint8_t ram_sizes[4][2][16] = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x30, 0x00, 0x10, 0x20, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 } },
|
||||
{ { 0x00, 0x00, 0x10, 0x10, 0x10, 0x40, 0x10, 0x10,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00 },
|
||||
{ 0x40, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10,
|
||||
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 } },
|
||||
{ { 0x00, 0x00, 0x00, 0x10, 0x10, 0x00, 0x40, 0x40,
|
||||
0x30, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00 },
|
||||
{ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,
|
||||
0x00, 0x10, 0x10, 0x30, 0x40, 0x40, 0x40, 0x40 } },
|
||||
{ { 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x10,
|
||||
0x00, 0x00, 0x10, 0x20, 0x30, 0x40, 0x00, 0x00 },
|
||||
{ 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
|
||||
0x00, 0x00, 0x10, 0x00, 0x00, 0x10, 0x20, 0x30 } } };
|
||||
uint8_t size;
|
||||
uint8_t start;
|
||||
uint8_t end;
|
||||
uint8_t k;
|
||||
uint32_t virt_base;
|
||||
uint32_t virt_addr;
|
||||
uint32_t phys_addr;
|
||||
cpq_ram_t *cram;
|
||||
|
||||
for (uint16_t i = 0x10; i < sys_min_high; i++)
|
||||
dev->mem_state[i] &= ~MEM_STATE_MASK;
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
for (uint8_t j = 0; j <= 64; j++) {
|
||||
if ((i >= 1) || (j >= 0x10))
|
||||
mem_mapping_disable(&dev->ram[i][j].mapping);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
size = ram_sizes[i][sys_ram][setup_port];
|
||||
if (size > 0x00) {
|
||||
start = ram_bases[i][sys_ram][setup_port];
|
||||
end = start + (size - 1);
|
||||
|
||||
virt_base = ((uint32_t) start) << 16;
|
||||
|
||||
for (uint16_t j = start; j <= end; j++) {
|
||||
k = j - start;
|
||||
if (i == 0)
|
||||
k += 0x10;
|
||||
|
||||
cram = &(dev->ram[i][k]);
|
||||
|
||||
dev->mem_state[j] |= ram_states[i];
|
||||
|
||||
cram->virt_base = ((uint32_t) j) << 16;
|
||||
cram->phys_base = cram->virt_base - virt_base + dev->ram_bases[i];
|
||||
|
||||
mem_mapping_set_addr(&cram->mapping, cram->virt_base, 0x00010000);
|
||||
mem_mapping_set_exec(&cram->mapping, &(ram[cram->phys_base]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Recalculate the entire 16 MB space. */
|
||||
cpq_recalc_states(dev);
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_write_regs(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
cpq_386_t *dev = (cpq_386_t *) priv;
|
||||
|
||||
addr &= 0x00000fff;
|
||||
|
||||
switch (addr) {
|
||||
case 0x00000000:
|
||||
case 0x00000001:
|
||||
/* RAM Relocation (Write Only) */
|
||||
dev->regs[addr + 4] = val;
|
||||
if (addr == 0x00000000) {
|
||||
dev->mem_state[0x0e] &= ~(MEM_STATE_SYS | MEM_STATE_WP);
|
||||
dev->mem_state[0x0f] &= ~(MEM_STATE_SYS | MEM_STATE_WP);
|
||||
dev->mem_state[0xfe] &= ~MEM_STATE_WP;
|
||||
dev->mem_state[0xff] &= ~MEM_STATE_WP;
|
||||
if (!(val & 0x01)) {
|
||||
dev->mem_state[0x0e] |= MEM_STATE_SYS;
|
||||
dev->mem_state[0x0f] |= MEM_STATE_SYS;
|
||||
}
|
||||
if (!(val & 0x02)) {
|
||||
dev->mem_state[0x0e] |= MEM_STATE_WP;
|
||||
dev->mem_state[0x0f] |= MEM_STATE_WP;
|
||||
dev->mem_state[0xfe] |= MEM_STATE_WP;
|
||||
dev->mem_state[0xff] |= MEM_STATE_WP;
|
||||
}
|
||||
cpq_recalc_state(dev, 0x0e);
|
||||
cpq_recalc_state(dev, 0x0f);
|
||||
cpq_recalc_state(dev, 0xfe);
|
||||
cpq_recalc_state(dev, 0xff);
|
||||
flushmmucache_nopc();
|
||||
}
|
||||
break;
|
||||
case 0x00000002:
|
||||
case 0x00000003:
|
||||
/* RAM Setup Port (Read/Write) */
|
||||
dev->regs[addr] = val;
|
||||
if (addr == 0x00000002) {
|
||||
cpq_recalc_ram(dev);
|
||||
cpq_recalc_cache(dev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_write_regsw(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
cpq_386_t *dev = (cpq_386_t *) priv;
|
||||
|
||||
cpq_write_regs(addr, val & 0xff, priv);
|
||||
cpq_write_regs(addr + 1, (val >> 8) & 0xff, priv);
|
||||
}
|
||||
|
||||
static void
|
||||
cpq_write_regsl(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
cpq_386_t *dev = (cpq_386_t *) priv;
|
||||
|
||||
cpq_write_regsw(addr, val & 0xff, priv);
|
||||
cpq_write_regsw(addr + 2, (val >> 16) & 0xff, priv);
|
||||
}
|
||||
|
||||
static void
|
||||
compaq_ram_init(cpq_ram_t *dev)
|
||||
{
|
||||
mem_mapping_add(&dev->mapping,
|
||||
0x00000000,
|
||||
0x00010000,
|
||||
cpq_read_ram,
|
||||
cpq_read_ramw,
|
||||
cpq_read_raml,
|
||||
cpq_write_ram,
|
||||
cpq_write_ramw,
|
||||
cpq_write_raml,
|
||||
NULL,
|
||||
MEM_MAPPING_INTERNAL,
|
||||
dev);
|
||||
|
||||
mem_mapping_disable(&dev->mapping);
|
||||
}
|
||||
|
||||
static void
|
||||
compaq_ram_diags_parse(cpq_386_t *dev)
|
||||
{
|
||||
uint8_t val = dev->regs[0x00000001];
|
||||
uint32_t accum = 0x00100000;
|
||||
|
||||
val;
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
dev->ram_bases[i] = accum;
|
||||
|
||||
switch (val & 0x03) {
|
||||
case RAM_DIAG_H_SYS_RAM_1MB:
|
||||
dev->ram_sizes[i] = 0x00100000;
|
||||
break;
|
||||
case RAM_DIAG_H_SYS_RAM_4MB:
|
||||
dev->ram_sizes[i] = 0x00400000;
|
||||
break;
|
||||
}
|
||||
if (i == 0)
|
||||
dev->ram_sizes[i] -= 0x00100000;
|
||||
|
||||
dev->ram_map_sizes[i] = dev->ram_sizes[i];
|
||||
accum += dev->ram_sizes[i];
|
||||
|
||||
if (accum >= (mem_size << 10)) {
|
||||
dev->ram_sizes[i] = (mem_size << 10) - dev->ram_bases[i];
|
||||
break;
|
||||
}
|
||||
|
||||
val >>= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compaq_recalc_base_ram(cpq_386_t *dev)
|
||||
{
|
||||
uint8_t base_mem = dev->regs[0x00000000] & RAM_DIAG_L_BASE_MEM_MASK;
|
||||
uint8_t sys_ram = dev->regs[0x00000001] & RAM_DIAG_H_SYS_RAM_MASK;
|
||||
uint8_t low_start = 0x00;
|
||||
uint8_t low_end = 0x00;
|
||||
uint8_t high_start = 0x00;
|
||||
uint8_t high_end = 0x00;
|
||||
uint32_t phys_addr = 0x00000000;
|
||||
uint32_t virt_addr = 0x00000000;
|
||||
cpq_ram_t *cram;
|
||||
|
||||
switch (base_mem) {
|
||||
case RAM_DIAG_L_BASE_MEM_256KB:
|
||||
switch (sys_ram) {
|
||||
case RAM_DIAG_H_SYS_RAM_1MB:
|
||||
low_start = 0x00;
|
||||
low_end = 0x03;
|
||||
high_start = 0xf4;
|
||||
high_end = 0xff;
|
||||
break;
|
||||
case RAM_DIAG_H_SYS_RAM_4MB:
|
||||
low_start = 0x00;
|
||||
low_end = 0x03;
|
||||
high_start = 0xfa;
|
||||
high_end = 0xff;
|
||||
break;
|
||||
default:
|
||||
fatal("Compaq 386 - Invalid configuation: %02X %02X\n", base_mem, sys_ram);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case RAM_DIAG_L_BASE_MEM_512KB:
|
||||
switch (sys_ram) {
|
||||
case RAM_DIAG_H_SYS_RAM_1MB:
|
||||
low_start = 0x00;
|
||||
low_end = 0x07;
|
||||
high_start = 0xf8;
|
||||
high_end = 0xff;
|
||||
break;
|
||||
case RAM_DIAG_H_SYS_RAM_4MB:
|
||||
low_start = 0x00;
|
||||
low_end = 0x07;
|
||||
high_start = 0xfa;
|
||||
high_end = 0xff;
|
||||
break;
|
||||
default:
|
||||
fatal("Compaq 386 - Invalid configuation: %02X %02X\n", base_mem, sys_ram);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case RAM_DIAG_L_BASE_MEM_640KB:
|
||||
switch (sys_ram) {
|
||||
case RAM_DIAG_H_SYS_RAM_1MB:
|
||||
low_start = 0x00;
|
||||
low_end = 0x09;
|
||||
high_start = 0xfa;
|
||||
high_end = 0xff;
|
||||
break;
|
||||
case RAM_DIAG_H_SYS_RAM_4MB:
|
||||
low_start = 0x00;
|
||||
low_end = 0x09;
|
||||
high_start = 0xfa;
|
||||
high_end = 0xff;
|
||||
break;
|
||||
default:
|
||||
fatal("Compaq 386 - Invalid configuation: %02X %02X\n", base_mem, sys_ram);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatal("Compaq 386 - Invalid configuation: %02X %02X\n", base_mem, sys_ram);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sys_ram) {
|
||||
case RAM_DIAG_H_SYS_RAM_1MB:
|
||||
if (mem_size < 1024)
|
||||
dev->regs[0x00000002] = 0x01;
|
||||
else if (mem_size == 8192)
|
||||
dev->regs[0x00000002] = 0x09;
|
||||
else if (mem_size >= 11264)
|
||||
dev->regs[0x00000002] = 0x0d;
|
||||
else
|
||||
dev->regs[0x00000002] = (mem_size >> 10);
|
||||
break;
|
||||
case RAM_DIAG_H_SYS_RAM_4MB:
|
||||
if (mem_size < 4096)
|
||||
dev->regs[0x00000002] = 0x04;
|
||||
else if (mem_size == 11264)
|
||||
dev->regs[0x00000002] = 0x0c;
|
||||
else if (mem_size >= 16384)
|
||||
dev->regs[0x00000002] = 0x00;
|
||||
else if (mem_size > 13312)
|
||||
dev->regs[0x00000002] = 0x0d;
|
||||
else
|
||||
dev->regs[0x00000002] = (mem_size >> 10);
|
||||
break;
|
||||
default:
|
||||
fatal("Compaq 386 - Invalid configuation: %02X\n", sys_ram);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The base 640 kB. */
|
||||
for (uint8_t i = low_start; i <= low_end; i++) {
|
||||
cram = &(dev->ram[0][i]);
|
||||
|
||||
cram->phys_base = cram->virt_base = ((uint32_t) i) << 16;
|
||||
dev->mem_state[i] |= MEM_STATE_SYS;
|
||||
|
||||
mem_mapping_set_addr(&cram->mapping, cram->virt_base, 0x00010000);
|
||||
mem_mapping_set_exec(&cram->mapping, &(ram[cram->phys_base]));
|
||||
|
||||
cpq_recalc_state(dev, i);
|
||||
}
|
||||
|
||||
/* The relocated 128 kB. */
|
||||
for (uint8_t i = 0x0e; i <= 0x0f; i++) {
|
||||
cram = &(dev->ram[0][i]);
|
||||
|
||||
cram->phys_base = cram->virt_base = ((uint32_t) i) << 16;
|
||||
|
||||
mem_mapping_set_addr(&cram->mapping, cram->virt_base, 0x00010000);
|
||||
mem_mapping_set_exec(&cram->mapping, &(ram[cram->phys_base]));
|
||||
}
|
||||
|
||||
/* Blocks FA-FF. */
|
||||
for (uint16_t i = high_start; i <= high_end; i++) {
|
||||
cram = &(dev->high_ram[i & 0x0f]);
|
||||
|
||||
cram->phys_base = ((uint32_t) (i & 0x0f)) << 16;
|
||||
cram->virt_base = ((uint32_t) i) << 16;
|
||||
dev->mem_state[i] |= MEM_STATE_SYS;
|
||||
|
||||
mem_mapping_set_addr(&cram->mapping, cram->virt_base, 0x00010000);
|
||||
mem_mapping_set_exec(&cram->mapping, &(ram[cram->phys_base]));
|
||||
|
||||
cpq_recalc_state(dev, i);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
compaq_386_close(void *priv)
|
||||
{
|
||||
cpq_386_t *dev = (cpq_386_t *) priv;
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
static void *
|
||||
compaq_386_init(const device_t *info)
|
||||
{
|
||||
cpq_386_t *dev = (cpq_386_t *) calloc(1, sizeof(cpq_386_t));
|
||||
|
||||
mem_mapping_add(&dev->regs_mapping,
|
||||
0x80c00000,
|
||||
0x00001000,
|
||||
cpq_read_regs,
|
||||
cpq_read_regsw,
|
||||
cpq_read_regsl,
|
||||
cpq_write_regs,
|
||||
cpq_write_regsw,
|
||||
cpq_write_regsl,
|
||||
NULL,
|
||||
MEM_MAPPING_INTERNAL,
|
||||
dev);
|
||||
|
||||
mem_set_mem_state(0x80c00000, 0x00001000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
||||
|
||||
dev->regs[0x00000000] = RAM_DIAG_L_PERMA_BITS;
|
||||
if (mem_size >= 640)
|
||||
dev->regs[0x00000000] |= RAM_DIAG_L_BASE_MEM_640KB;
|
||||
else if (mem_size >= 512)
|
||||
dev->regs[0x00000000] |= RAM_DIAG_L_BASE_MEM_512KB;
|
||||
else if (mem_size >= 256)
|
||||
dev->regs[0x00000000] |= RAM_DIAG_L_BASE_MEM_256KB;
|
||||
else
|
||||
dev->regs[0x00000000] |= RAM_DIAG_L_BASE_MEM_INV;
|
||||
/* Indicate no parity error. */
|
||||
dev->regs[0x00000000] |= 0x0f;
|
||||
|
||||
if (mem_size >= 1024) {
|
||||
switch (mem_size) {
|
||||
case 1024:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_NONE |
|
||||
RAM_DIAG_H_MOD_B_RAM_NONE | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 2048:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_NONE |
|
||||
RAM_DIAG_H_MOD_B_RAM_NONE | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 3072:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_NONE |
|
||||
RAM_DIAG_H_MOD_B_RAM_NONE | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 4096:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_NONE |
|
||||
RAM_DIAG_H_MOD_B_RAM_NONE | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 5120:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_1MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_NONE | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 6144:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_1MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_1MB | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 7168:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_1MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_1MB | RAM_DIAG_H_MOD_C_RAM_1MB;
|
||||
break;
|
||||
case 8192:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_4MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_NONE | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 9216:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_4MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_1MB | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 10240:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_4MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_1MB | RAM_DIAG_H_MOD_C_RAM_1MB;
|
||||
break;
|
||||
case 11264:
|
||||
case 12288:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_4MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_4MB | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
break;
|
||||
case 13312:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_4MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_4MB | RAM_DIAG_H_MOD_C_RAM_1MB;
|
||||
break;
|
||||
case 14336:
|
||||
case 15360:
|
||||
case 16384:
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_4MB | RAM_DIAG_H_MOD_A_RAM_4MB |
|
||||
RAM_DIAG_H_MOD_B_RAM_4MB | RAM_DIAG_H_MOD_C_RAM_4MB;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
dev->regs[0x00000001] = RAM_DIAG_H_SYS_RAM_1MB | RAM_DIAG_H_MOD_A_RAM_NONE |
|
||||
RAM_DIAG_H_MOD_B_RAM_NONE | RAM_DIAG_H_MOD_C_RAM_NONE;
|
||||
|
||||
dev->regs[0x00000003] = 0xfc;
|
||||
dev->regs[0x00000004] = dev->regs[0x00000005] = 0xff;
|
||||
|
||||
compaq_ram_diags_parse(dev);
|
||||
|
||||
mem_mapping_disable(&ram_low_mapping);
|
||||
mem_mapping_disable(&ram_mid_mapping);
|
||||
mem_mapping_disable(&ram_high_mapping);
|
||||
#if (!(defined __amd64__ || defined _M_X64 || defined __aarch64__ || defined _M_ARM64))
|
||||
/* Should never be the case, but you never know what a user may set. */
|
||||
if (mem_size > 1048576)
|
||||
mem_mapping_disable(&ram_2gb_mapping);
|
||||
#endif
|
||||
|
||||
/* Initialize in reverse order for memory mapping precedence
|
||||
reasons. */
|
||||
for (int8_t i = 3; i >= 0; i--) {
|
||||
for (uint8_t j = 0; j < 64; j++)
|
||||
compaq_ram_init(&(dev->ram[i][j]));
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < 16; i++)
|
||||
compaq_ram_init(&(dev->high_ram[i]));
|
||||
|
||||
/* First, set the entire 256 MB of space to invalid states. */
|
||||
for (uint16_t i = 0; i < 256; i++)
|
||||
dev->old_state[i] = 0xff;
|
||||
|
||||
/* Then, recalculate the base RAM mappings. */
|
||||
compaq_recalc_base_ram(dev);
|
||||
|
||||
/* Enable the external cache. */
|
||||
dev->regs[0x00000002] |= 0x40;
|
||||
cpq_recalc_cache(dev);
|
||||
|
||||
/* Recalculate the rest of the RAM mapping. */
|
||||
cpq_recalc_ram(dev);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
const device_t compaq_386_device = {
|
||||
.name = "Compaq 386 Memory Control",
|
||||
.internal_name = "opti391",
|
||||
.flags = 0,
|
||||
.local = 0,
|
||||
.init = compaq_386_init,
|
||||
.close = compaq_386_close,
|
||||
.reset = NULL,
|
||||
{ .available = NULL },
|
||||
.speed_changed = NULL,
|
||||
.force_redraw = NULL,
|
||||
.config = NULL
|
||||
};
|
Reference in New Issue
Block a user