Files
86Box/src/device/isamem.c
2024-06-07 18:23:16 +02:00

2148 lines
64 KiB
C

/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
*
* Implementation of a memory expansion board for the ISA Bus.
*
* Although modern systems use direct-connect local buses to
* connect the CPU with its memory, originally the main system
* bus(es) were used for that. Memory expension cards could add
* memory to the system through the ISA bus, using a variety of
* techniques.
*
* The majority of these boards could provide some (additional)
* conventional (low) memory, extended (high) memory on 80286
* and higher systems, as well as EMS bank-switched memory.
*
* This implementation uses the LIM 3.2 specifications for EMS.
*
* With the EMS method, the system's standard memory is expanded
* by means of bank-switching. One or more 'frames' in the upper
* memory area (640K-1024K) are used as viewports into an array
* of RAM pages numbered 0 to N. Each page is defined to be 16KB
* in size, so, for a 1024KB board, 64 such pages are available.
* I/O control registers are used to set up the mappings. More
* modern boards even have multiple 'copies' of those registers,
* which can be switched very fast, to allow for multitasking.
*
* TODO: The EV159 is supposed to support 16b EMS transfers, but the
* EMM.sys driver for it doesn't seem to want to do that..
*
*
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Jasmine Iwanek <jriwanek@gmail.com>
*
* Copyright 2018 Fred N. van Kempen.
* Copyright 2022-2024 Jasmine Iwanek.
*
* Redistribution and use in source and binary forms, with
* or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the entire
* above notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names
* of its contributors may be used to endorse or promote
* products derived from this software without specific
* prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/machine.h>
#include <86box/io.h>
#include <86box/mem.h>
#include <86box/device.h>
#include <86box/ui.h>
#include <86box/plat.h>
#include <86box/isamem.h>
#include "cpu.h"
#define ISAMEM_IBMXT_CARD 0
#define ISAMEM_GENXT_CARD 1
#define ISAMEM_RAMCARD_CARD 2
#define ISAMEM_SYSTEMCARD_CARD 3
#define ISAMEM_IBMAT_128K_CARD 4
#define ISAMEM_IBMAT_CARD 5
#define ISAMEM_GENAT_CARD 6
#define ISAMEM_P5PAK_CARD 7
#define ISAMEM_A6PAK_CARD 8
#define ISAMEM_EMS5150_CARD 9
#define ISAMEM_EV159_CARD 10
#define ISAMEM_RAMPAGEXT_CARD 11
#define ISAMEM_ABOVEBOARD_CARD 12
#define ISAMEM_BRXT_CARD 13
#define ISAMEM_BRAT_CARD 14
#define ISAMEM_EV165A_CARD 15
#define ISAMEM_LOTECH_CARD 16
#define ISAMEM_DEBUG 0
#define RAM_TOPMEM (640 << 10) /* end of low memory */
#define RAM_UMAMEM (384 << 10) /* upper memory block */
#define RAM_EXTMEM (1024 << 10) /* start of high memory */
#define EMS_MAXSIZE (2048 << 10) /* max EMS memory size */
#define EMS_EV159_MAXSIZE (3072 << 10) /* max EMS memory size for EV-159 cards */
#define EMS_LOTECH_MAXSIZE (4096 << 10) /* max EMS memory size for lotech cards */
#define EMS_PGSIZE (16 << 10) /* one page is this big */
#define EMS_MAXPAGE 4 /* number of viewport pages */
#define EXTRAM_CONVENTIONAL 0
#define EXTRAM_HIGH 1
#define EXTRAM_XMS 2
typedef struct emsreg_t {
int8_t enabled; /* 1=ENABLED */
uint8_t page; /* page# in EMS RAM */
uint8_t frame; /* (varies with board) */
char pad;
uint8_t *addr; /* start addr in EMS RAM */
mem_mapping_t mapping; /* mapping entry for page */
uint8_t *ram;
uint8_t *frame_val;
uint16_t *ems_size;
uint16_t *ems_pages;
uint32_t *frame_addr;
} emsreg_t;
typedef struct ext_ram_t {
uint32_t base;
uint8_t *ptr;
} ext_ram_t;
typedef struct memdev_t {
const char *name;
uint8_t board : 6; /* board type */
uint8_t reserved : 2;
uint8_t flags;
#define FLAG_CONFIG 0x01 /* card is configured */
#define FLAG_WIDE 0x10 /* card uses 16b mode */
#define FLAG_FAST 0x20 /* fast (<= 120ns) chips */
#define FLAG_EMS 0x40 /* card has EMS mode enabled */
uint8_t frame_val[2];
uint16_t total_size; /* configured size in KB */
uint16_t base_addr[2]; /* configured I/O address */
uint32_t start_addr; /* configured memory start */
uint32_t frame_addr[2]; /* configured frame address */
uint16_t ems_size[2]; /* EMS size in KB */
uint16_t ems_pages[2]; /* EMS size in pages */
uint32_t ems_start[2]; /* start of EMS in RAM */
uint8_t *ram; /* allocated RAM buffer */
ext_ram_t ext_ram[3]; /* structures for the mappings */
mem_mapping_t low_mapping; /* mapping for low mem */
mem_mapping_t high_mapping; /* mapping for high mem */
emsreg_t ems[EMS_MAXPAGE * 2]; /* EMS controller registers */
} memdev_t;
#ifdef ENABLE_ISAMEM_LOG
int isamem_do_log = ENABLE_ISAMEM_LOG;
static void
isamem_log(const char *fmt, ...)
{
va_list ap;
if (isamem_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define isamem_log(fmt, ...)
#endif
/* Why this convoluted setup with the mem_dev stuff when it's much simpler
to just pass the exec pointer as p as well, and then just use that. */
/* Read one byte from onboard RAM. */
static uint8_t
ram_readb(uint32_t addr, void *priv)
{
ext_ram_t *dev = (ext_ram_t *) priv;
uint8_t ret = 0xff;
/* Grab the data. */
ret = *(uint8_t *) (dev->ptr + (addr - dev->base));
return ret;
}
/* Read one word from onboard RAM. */
static uint16_t
ram_readw(uint32_t addr, void *priv)
{
ext_ram_t *dev = (ext_ram_t *) priv;
uint16_t ret = 0xffff;
/* Grab the data. */
ret = *(uint16_t *) (dev->ptr + (addr - dev->base));
return ret;
}
/* Write one byte to onboard RAM. */
static void
ram_writeb(uint32_t addr, uint8_t val, void *priv)
{
ext_ram_t *dev = (ext_ram_t *) priv;
/* Write the data. */
*(uint8_t *) (dev->ptr + (addr - dev->base)) = val;
}
/* Write one word to onboard RAM. */
static void
ram_writew(uint32_t addr, uint16_t val, void *priv)
{
ext_ram_t *dev = (ext_ram_t *) priv;
/* Write the data. */
*(uint16_t *) (dev->ptr + (addr - dev->base)) = val;
}
/* Read one byte from onboard paged RAM. */
static uint8_t
ems_readb(uint32_t addr, void *priv)
{
emsreg_t *dev = (emsreg_t *) priv;
uint8_t ret = 0xff;
/* Grab the data. */
ret = *(uint8_t *) (dev->addr + (addr & 0x3fff));
#if ISAMEM_DEBUG
if ((addr % 4096) == 0)
isamem_log("EMS readb(%06x) = %02x\n", addr & 0x3fff, ret);
#endif
return ret;
}
/* Read one word from onboard paged RAM. */
static uint16_t
ems_readw(uint32_t addr, void *priv)
{
emsreg_t *dev = (emsreg_t *) priv;
uint16_t ret = 0xffff;
/* Grab the data. */
ret = *(uint16_t *) (dev->addr + (addr & 0x3fff));
#if ISAMEM_DEBUG
if ((addr % 4096) == 0)
isamem_log("EMS readw(%06x) = %04x\n", addr & 0x3fff, ret);
#endif
return ret;
}
/* Write one byte to onboard paged RAM. */
static void
ems_writeb(uint32_t addr, uint8_t val, void *priv)
{
emsreg_t *dev = (emsreg_t *) priv;
/* Write the data. */
#if ISAMEM_DEBUG
if ((addr % 4096) == 0)
isamem_log("EMS writeb(%06x, %02x)\n", addr & 0x3fff, val);
#endif
*(uint8_t *) (dev->addr + (addr & 0x3fff)) = val;
}
/* Write one word to onboard paged RAM. */
static void
ems_writew(uint32_t addr, uint16_t val, void *priv)
{
emsreg_t *dev = (emsreg_t *) priv;
/* Write the data. */
#if ISAMEM_DEBUG
if ((addr % 4096) == 0)
isamem_log("EMS writew(%06x, %04x)\n", addr & 0x3fff, val);
#endif
*(uint16_t *) (dev->addr + (addr & 0x3fff)) = val;
}
/* Handle a READ operation from one of our registers. */
static uint8_t
ems_in(uint16_t port, void *priv)
{
const emsreg_t *dev = (emsreg_t *) priv;
uint8_t ret = 0xff;
#ifdef ENABLE_ISAMEM_LOG
int vpage;
#endif
/* Get the viewport page number. */
#ifdef ENABLE_ISAMEM_LOG
vpage = (port / EMS_PGSIZE);
#endif
port &= (EMS_PGSIZE - 1);
switch (port & 0x0001) {
case 0x0000: /* page number register */
ret = dev->page;
if (dev->enabled)
ret |= 0x80;
break;
case 0x0001: /* W/O */
break;
default:
break;
}
isamem_log("ISAMEM: read(%04x) = %02x) page=%d\n", port, ret, vpage);
return ret;
}
/* Handle a READ operation from one of our registers. */
static uint8_t
consecutive_ems_in(uint16_t port, void *priv)
{
const memdev_t *dev = (memdev_t *) priv;
uint8_t ret = 0xff;
int vpage;
/* Get the viewport page number. */
vpage = (port - dev->base_addr[0]);
ret = dev->ems[vpage].page;
if (dev->ems[vpage].enabled)
ret |= 0x80;
isamem_log("ISAMEM: read(%04x) = %02x) page=%d\n", port, ret, vpage);
return ret;
}
/* Handle a WRITE operation to one of our registers. */
static void
ems_out(uint16_t port, uint8_t val, void *priv)
{
emsreg_t *dev = (emsreg_t *) priv;
int vpage;
/* Get the viewport page number. */
vpage = (port / EMS_PGSIZE);
port &= (EMS_PGSIZE - 1);
switch (port & 0x0001) {
case 0x0000: /* page mapping registers */
/* Set the page number. */
dev->enabled = (val & 0x80);
dev->page = (val & 0x7f);
if (dev->enabled && (dev->page < *dev->ems_pages)) {
/* Pre-calculate the page address in EMS RAM. */
dev->addr = dev->ram + ((val & 0x7f) * EMS_PGSIZE);
isamem_log("ISAMEM: map port %04X, page %i, starting at %08X: %08X -> %08X\n", port,
vpage, *dev->frame_addr,
*dev->frame_addr + (EMS_PGSIZE * (vpage & 3)), dev->addr - dev->ram);
mem_mapping_set_addr(&dev->mapping, *dev->frame_addr + (EMS_PGSIZE * vpage), EMS_PGSIZE);
/* Update the EMS RAM address for this page. */
mem_mapping_set_exec(&dev->mapping, dev->addr);
/* Enable this page. */
mem_mapping_enable(&dev->mapping);
} else {
isamem_log("ISAMEM: map port %04X, page %i, starting at %08X: %08X -> N/A\n",
port, vpage, *dev->frame_addr, *dev->frame_addr + (EMS_PGSIZE * vpage));
/* Disable this page. */
mem_mapping_disable(&dev->mapping);
}
break;
case 0x0001: /* page frame registers */
/*
* The EV-159 EMM driver configures the frame address
* by setting bits in these registers. The information
* in their manual is unclear, but here is what was
* found out by repeatedly changing EMM's config:
*
* 08 04 00 Address
* -----------------
* 00 00 00 C4000
* 00 00 80 C8000
* 00 80 00 CC000
* 00 80 80 D0000
* 80 00 00 D4000
* 80 00 80 D8000
* 80 80 00 DC000
* 80 80 80 E0000
*/
dev->frame = val;
*dev->frame_val = (*dev->frame_val & ~(1 << vpage)) | ((val >> 7) << vpage);
*dev->frame_addr = 0x000c4000 + (*dev->frame_val << 14);
isamem_log("ISAMEM: map port %04X page %i: frame_addr = %08X\n", port, vpage, *dev->frame_addr);
/* Destroy the page registers. */
for (uint8_t i = 0; i < 4; i ++) {
isamem_log(" ");
outb((port & 0x3ffe) + (i << 14), 0x00);
}
break;
default:
break;
}
}
/* Handle a WRITE operation to one of our registers. */
static void
consecutive_ems_out(uint16_t port, uint8_t val, void *priv)
{
memdev_t *dev = (memdev_t *) priv;
int vpage;
/* Get the viewport page number. */
vpage = (port - dev->base_addr[0]);
isamem_log("ISAMEM: write(%04x, %02x) to page mapping registers! (page=%d)\n", port, val, vpage);
/* Set the page number. */
dev->ems[vpage].enabled = 1;
dev->ems[vpage].page = val;
/* Make sure we can do that.. */
if (dev->flags & FLAG_CONFIG) {
if (dev->ems[vpage].page < dev->ems_pages[0]) {
/* Pre-calculate the page address in EMS RAM. */
dev->ems[vpage].addr = dev->ram + dev->ems_start[0] + (val * EMS_PGSIZE);
} else {
/* That page does not exist. */
dev->ems[vpage].enabled = 0;
}
if (dev->ems[vpage].enabled) {
/* Update the EMS RAM address for this page. */
mem_mapping_set_exec(&dev->ems[vpage].mapping,
dev->ems[vpage].addr);
/* Enable this page. */
mem_mapping_enable(&dev->ems[vpage].mapping);
} else {
/* Disable this page. */
mem_mapping_disable(&dev->ems[vpage].mapping);
}
}
}
/* Initialize the device for use. */
static void *
isamem_init(const device_t *info)
{
memdev_t *dev;
uint32_t k;
uint32_t t;
uint32_t addr;
uint32_t tot;
/* EMS 3.2 cannot have more than 2048KB per board. */
uint32_t ems_max = EMS_MAXSIZE;
uint8_t *ptr;
/* Find our device and create an instance. */
dev = (memdev_t *) malloc(sizeof(memdev_t));
memset(dev, 0x00, sizeof(memdev_t));
dev->name = info->name;
dev->board = info->local;
dev->base_addr[1] = 0x0000;
dev->frame_addr[1] = 0x00000000;
/* Do per-board initialization. */
tot = 0;
switch (dev->board) {
case ISAMEM_IBMXT_CARD: /* IBM PC/XT Memory Expansion Card */
case ISAMEM_GENXT_CARD: /* Generic PC/XT Memory Expansion Card */
case ISAMEM_RAMCARD_CARD: /* Microsoft RAMCard for IBM PC */
case ISAMEM_SYSTEMCARD_CARD: /* Microsoft SystemCard */
case ISAMEM_P5PAK_CARD: /* Paradise Systems 5-PAK */
case ISAMEM_A6PAK_CARD: /* AST SixPakPlus */
dev->total_size = device_get_config_int("size");
dev->start_addr = device_get_config_int("start");
tot = dev->total_size;
break;
case ISAMEM_IBMAT_128K_CARD: /* IBM PC/AT 128K Memory Expansion Option */
dev->total_size = 128;
dev->start_addr = 512;
tot = dev->total_size;
dev->flags |= FLAG_WIDE;
break;
case ISAMEM_IBMAT_CARD: /* IBM PC/AT Memory Expansion Card */
case ISAMEM_GENAT_CARD: /* Generic PC/AT Memory Expansion Card */
dev->total_size = device_get_config_int("size");
dev->start_addr = device_get_config_int("start");
tot = dev->total_size;
dev->flags |= FLAG_WIDE;
break;
case ISAMEM_EMS5150_CARD: /* Micro Mainframe EMS-5150(T) */
dev->base_addr[0] = device_get_config_hex16("base");
dev->total_size = device_get_config_int("size");
dev->start_addr = 0;
dev->frame_addr[0] = 0xd0000;
dev->flags |= (FLAG_EMS | FLAG_CONFIG);
break;
case ISAMEM_EV159_CARD: /* Everex EV-159 RAM 3000 */
/* The EV-159 cannot have more than 3072KB per board. */
ems_max = EMS_EV159_MAXSIZE;
dev->base_addr[0] = device_get_config_hex16("base");
dev->base_addr[1] = device_get_config_hex16("base2");
dev->total_size = device_get_config_int("size");
dev->start_addr = device_get_config_int("start");
tot = device_get_config_int("length");
if (!!device_get_config_int("width"))
dev->flags |= FLAG_WIDE;
if (!!device_get_config_int("speed"))
dev->flags |= FLAG_FAST;
if (!!device_get_config_int("ems"))
dev->flags |= FLAG_EMS;
dev->frame_addr[0] = 0xd0000;
dev->frame_addr[1] = 0xe0000;
break;
case ISAMEM_EV165A_CARD: /* Everex Maxi Magic EV-165A */
dev->base_addr[0] = device_get_config_hex16("base");
dev->total_size = device_get_config_int("size");
dev->start_addr = device_get_config_int("start");
tot = device_get_config_int("length");
if (!!device_get_config_int("ems"))
dev->flags |= FLAG_EMS;
dev->frame_addr[0] = 0xe0000;
break;
case ISAMEM_RAMPAGEXT_CARD: /* AST RAMpage/XT */
dev->base_addr[0] = device_get_config_hex16("base");
dev->total_size = device_get_config_int("size");
dev->start_addr = device_get_config_int("start");
tot = dev->total_size;
dev->flags |= FLAG_EMS;
dev->frame_addr[0] = 0xe0000;
break;
case ISAMEM_ABOVEBOARD_CARD: /* Intel AboveBoard */
case ISAMEM_BRAT_CARD: /* BocaRAM/AT */
dev->base_addr[0] = device_get_config_hex16("base");
dev->total_size = device_get_config_int("size");
if (!!device_get_config_int("start"))
dev->start_addr = device_get_config_int("start");
dev->frame_addr[0] = device_get_config_hex20("frame");
dev->flags |= FLAG_EMS;
if (!!device_get_config_int("width"))
dev->flags |= FLAG_WIDE;
if (!!device_get_config_int("speed"))
dev->flags |= FLAG_FAST;
break;
case ISAMEM_LOTECH_CARD: /* Lotech EMS */
/* The Lotech EMS cannot have more than 4096KB per board. */
ems_max = EMS_LOTECH_MAXSIZE;
fallthrough;
case ISAMEM_BRXT_CARD: /* BocaRAM/XT */
dev->base_addr[0] = device_get_config_hex16("base");
dev->total_size = device_get_config_int("size");
dev->start_addr = 0;
dev->frame_addr[0] = device_get_config_hex20("frame");
dev->flags |= (FLAG_EMS | FLAG_CONFIG);
break;
default:
break;
}
/* Fix up the memory start address. */
dev->start_addr <<= 10;
/* Say hello! */
isamem_log("ISAMEM: %s (%iKB", info->name, dev->total_size);
if (tot && (dev->total_size != tot))
isamem_log(", %iKB for RAM", tot);
if (dev->flags & FLAG_FAST)
isamem_log(", FAST");
if (dev->flags & FLAG_WIDE)
isamem_log(", 16BIT");
isamem_log(")\n");
/* Force (back to) 8-bit bus if needed. */
if ((!is286) && (dev->flags & FLAG_WIDE)) {
isamem_log("ISAMEM: not AT+ system, forcing 8-bit mode!\n");
dev->flags &= ~FLAG_WIDE;
}
/* Allocate and initialize our RAM. */
k = dev->total_size << 10;
dev->ram = (uint8_t *) malloc(k);
memset(dev->ram, 0x00, k);
ptr = dev->ram;
/*
* The 'Memory Start Address' switch indicates at which address
* we should start adding memory. No memory is added if it is
* set to 0.
*/
tot <<= 10;
addr = dev->start_addr;
if (addr > 0 && tot > 0) {
/* Adjust K for the RAM we will use. */
k -= tot;
/*
* First, see if we have to expand the conventional
* (low) memory area. This can extend up to 640KB,
* so check this first.
*/
t = (addr < RAM_TOPMEM) ? RAM_TOPMEM - addr : 0;
if (t > 0) {
/*
* We need T bytes to extend that area.
*
* If the board doesn't have that much, grab
* as much as we can.
*/
if (t > tot)
t = tot;
isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr >> 10, t >> 10);
dev->ext_ram[EXTRAM_CONVENTIONAL].ptr = ptr;
dev->ext_ram[EXTRAM_CONVENTIONAL].base = addr;
/* Create, initialize and enable the low-memory mapping. */
mem_mapping_add(&dev->low_mapping, addr, t,
ram_readb,
(dev->flags & FLAG_WIDE) ? ram_readw : NULL,
NULL,
ram_writeb,
(dev->flags & FLAG_WIDE) ? ram_writew : NULL,
NULL,
ptr, MEM_MAPPING_EXTERNAL, &dev->ext_ram[EXTRAM_CONVENTIONAL]);
/* Tell the memory system this is external RAM. */
mem_set_mem_state(addr, t,
MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
/* Update pointers. */
ptr += t;
tot -= t;
addr += t;
}
/* Skip to high memory if needed. */
if ((addr == RAM_TOPMEM) && (tot >= RAM_UMAMEM)) {
/*
* We have more RAM available, but we are at the
* top of conventional RAM. So, the next 384K are
* skipped, and placed into different mappings so
* they can be re-mapped later.
*/
t = RAM_UMAMEM; /* 384KB */
isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr >> 10, t >> 10);
dev->ext_ram[EXTRAM_HIGH].ptr = ptr;
dev->ext_ram[EXTRAM_HIGH].base = addr + tot;
/* Update and enable the remap. */
mem_mapping_set(&ram_remapped_mapping,
addr + tot, t,
ram_readb, ram_readw, NULL,
ram_writeb, ram_writew, NULL,
ptr, MEM_MAPPING_EXTERNAL,
&dev->ext_ram[EXTRAM_HIGH]);
mem_mapping_disable(&ram_remapped_mapping);
/* Tell the memory system this is external RAM. */
mem_set_mem_state(addr + tot, t,
MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
/* Update pointers. */
ptr += t;
tot -= t;
addr += t;
}
}
/*
* Next, on systems that support it (80286 and up), we can add
* (some of) our RAM to the system as Extended Memory, that is,
* memory located above 1MB. This memory cannot be addressed in
* real mode (so, not by DOS, for example) but it can be used in
* protected mode.
*/
if (is286 && addr > 0 && tot > 0) {
t = tot;
isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr >> 10, t >> 10);
dev->ext_ram[EXTRAM_XMS].ptr = ptr;
dev->ext_ram[EXTRAM_XMS].base = addr;
/* Create, initialize and enable the high-memory mapping. */
mem_mapping_add(&dev->high_mapping, addr, t,
ram_readb, ram_readw, NULL,
ram_writeb, ram_writew, NULL,
ptr, MEM_MAPPING_EXTERNAL, &dev->ext_ram[EXTRAM_XMS]);
/* Tell the memory system this is external RAM. */
mem_set_mem_state(addr, t, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
/* Update pointers. */
ptr += t;
tot -= t;
addr += t;
}
isa_mem_size += dev->total_size - (k >> 10);
/* If EMS is enabled, use the remainder for EMS. */
if (dev->flags & FLAG_EMS) {
t = k;
if (t > ems_max)
t = ems_max;
/* Set up where EMS begins in local RAM, and how much we have. */
dev->ems_start[0] = ptr - dev->ram;
if ((dev->board == ISAMEM_EV159_CARD) && (t > (2 << 20))) {
dev->ems_size[0] = 2 << 10;
dev->ems_pages[0] = (2 << 20) / EMS_PGSIZE;
} else {
dev->ems_size[0] = t >> 10;
dev->ems_pages[0] = t / EMS_PGSIZE;
}
isamem_log("ISAMEM: EMS #1 enabled, I/O=%04XH, %iKB (%i pages)",
dev->base_addr[0], dev->ems_size[0], dev->ems_pages[0]);
if (dev->frame_addr[0] > 0)
isamem_log(", Frame[0]=%05XH", dev->frame_addr[0]);
isamem_log("\n");
if ((dev->board == ISAMEM_EV159_CARD) && (t > (2 << 20))) {
dev->ems_start[1] = dev->ems_start[0] + (2 << 20);
dev->ems_size[1] = (t - (2 << 20)) >> 10;
dev->ems_pages[1] = (t - (2 << 20)) / EMS_PGSIZE;
isamem_log("ISAMEM: EMS #2 enabled, I/O=%04XH, %iKB (%i pages)",
dev->base_addr[1], dev->ems_size[1], dev->ems_pages[1]);
if (dev->frame_addr[1] > 0)
isamem_log(", Frame[1]=%05XH", dev->frame_addr[1]);
isamem_log("\n");
}
/*
* For each supported page (we can have a maximum of 4),
* create, initialize and disable the mappings, and set
* up the I/O control handler.
*/
for (uint8_t i = 0; i < EMS_MAXPAGE; i++) {
dev->ems[i].ram = dev->ram + dev->ems_start[0];
dev->ems[i].frame_val = &dev->frame_val[0];
dev->ems[i].ems_size = &dev->ems_size[0];
dev->ems[i].ems_pages = &dev->ems_pages[0];
dev->ems[i].frame_addr = &dev->frame_addr[0];
/* Create and initialize a page mapping. */
mem_mapping_add(&dev->ems[i].mapping,
dev->frame_addr[0] + (EMS_PGSIZE * i), EMS_PGSIZE,
ems_readb,
(dev->flags & FLAG_WIDE) ? ems_readw : NULL,
NULL,
ems_writeb,
(dev->flags & FLAG_WIDE) ? ems_writew : NULL,
NULL,
ptr, MEM_MAPPING_EXTERNAL,
&(dev->ems[i]));
/* For now, disable it. */
mem_mapping_disable(&dev->ems[i].mapping);
/* Set up an I/O port handler. */
if (dev->board != ISAMEM_LOTECH_CARD)
io_sethandler(dev->base_addr[0] + (EMS_PGSIZE * i), 2,
ems_in, NULL, NULL, ems_out, NULL, NULL, &(dev->ems[i]));
if ((dev->board == ISAMEM_EV159_CARD) && (t > (2 << 20))) {
dev->ems[i | 4].ram = dev->ram + dev->ems_start[1];
dev->ems[i | 4].frame_val = &dev->frame_val[1];
dev->ems[i | 4].ems_size = &dev->ems_size[1];
dev->ems[i | 4].ems_pages = &dev->ems_pages[1];
dev->ems[i | 4].frame_addr = &dev->frame_addr[1];
/* Create and initialize a page mapping. */
mem_mapping_add(&dev->ems[i | 4].mapping,
dev->frame_addr[1] + (EMS_PGSIZE * i), EMS_PGSIZE,
ems_readb,
(dev->flags & FLAG_WIDE) ? ems_readw : NULL,
NULL,
ems_writeb,
(dev->flags & FLAG_WIDE) ? ems_writew : NULL,
NULL,
ptr + (2 << 20), MEM_MAPPING_EXTERNAL,
&(dev->ems[i | 4]));
/* For now, disable it. */
mem_mapping_disable(&dev->ems[i | 4].mapping);
io_sethandler(dev->base_addr[1] + (EMS_PGSIZE * i), 2,
ems_in, NULL, NULL, ems_out, NULL, NULL, &(dev->ems[i | 4]));
}
}
if (dev->board == ISAMEM_LOTECH_CARD)
io_sethandler(dev->base_addr[0], 4,
consecutive_ems_in, NULL, NULL, consecutive_ems_out, NULL, NULL, dev);
}
/* Let them know our device instance. */
return ((void *) dev);
}
/* Remove the device from the system. */
static void
isamem_close(void *priv)
{
memdev_t *dev = (memdev_t *) priv;
if (dev->ram != NULL)
free(dev->ram);
free(dev);
}
static const device_config_t ibmxt_32k_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 32,
.file_filter = "",
.spinner = {
.min = 32,
.max = 576,
.step = 32
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 64,
.file_filter = "",
.spinner = {
.min = 0,
.max = 608,
.step = 32
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t ibmxt_32k_device = {
.name = "IBM PC/XT 32K Memory Expansion Option",
.internal_name = "ibmxt_32k",
.flags = DEVICE_ISA,
.local = ISAMEM_IBMXT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = ibmxt_32k_config
};
static const device_config_t ibmxt_64k_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 64,
.file_filter = "",
.spinner = {
.min = 64,
.max = 576,
.step = 64
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 64,
.file_filter = "",
.spinner = {
.min = 0,
.max = 576,
.step = 64
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t ibmxt_64k_device = {
.name = "IBM PC/XT 64K Memory Expansion Option",
.internal_name = "ibmxt_64k",
.flags = DEVICE_ISA,
.local = ISAMEM_IBMXT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = ibmxt_64k_config
};
static const device_config_t ibmxt_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 128,
.file_filter = "",
.spinner = {
.min = 64,
.max = 576,
.step = 64
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 256,
.file_filter = "",
.spinner = {
.min = 0,
.max = 576,
.step = 64
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t ibmxt_device = {
.name = "IBM PC/XT 64/256K Memory Expansion Option",
.internal_name = "ibmxt",
.flags = DEVICE_ISA,
.local = ISAMEM_IBMXT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = ibmxt_config
};
static const device_config_t genericxt_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 16,
.file_filter = "",
.spinner = {
.min = 0,
.max = 640,
.step = 16
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = {
.min = 0,
.max = 624,
.step = 16
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t genericxt_device = {
.name = "Generic PC/XT Memory Expansion",
.internal_name = "genericxt",
.flags = DEVICE_ISA,
.local = ISAMEM_GENXT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = genericxt_config
};
static const device_config_t msramcard_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 64,
.file_filter = "",
.spinner = {
.min = 0,
.max = 256,
.step = 64
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = {
.min = 0,
.max = 624,
.step = 64
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t msramcard_device = {
.name = "Microsoft RAMCard for IBM PC",
.internal_name = "msramcard",
.flags = DEVICE_ISA,
.local = ISAMEM_RAMCARD_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = msramcard_config
};
static const device_config_t mssystemcard_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 64,
.file_filter = "",
.spinner = {
.min = 0,
.max = 256,
.step = 64
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = {
.min = 0,
.max = 624,
.step = 64
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t mssystemcard_device = {
.name = "Microsoft SystemCard",
.internal_name = "mssystemcard",
.flags = DEVICE_ISA,
.local = ISAMEM_SYSTEMCARD_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = mssystemcard_config
};
static const device_t ibmat_128k_device = {
.name = "IBM PC/AT 128KB Memory Expansion Option",
.internal_name = "ibmat_128k",
.flags = DEVICE_ISA,
.local = ISAMEM_IBMAT_128K_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
static const device_config_t ibmat_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 0,
.max = 12288,
.step = 512
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 0,
.max = 15872,
.step = 512
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t ibmat_device = {
.name = "IBM PC/AT Memory Expansion",
.internal_name = "ibmat",
.flags = DEVICE_ISA,
.local = ISAMEM_IBMAT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = ibmat_config
};
static const device_config_t genericat_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 0,
.max = 16384,
.step = 512
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 0,
.max = 15872,
.step = 128
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t genericat_device = {
.name = "Generic PC/AT Memory Expansion",
.internal_name = "genericat",
.flags = DEVICE_ISA,
.local = ISAMEM_GENAT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = genericat_config
};
static const device_config_t p5pak_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 128,
.file_filter = "",
.spinner = {
.min = 0,
.max = 384,
.step = 64
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 64,
.max = 576,
.step = 64
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t p5pak_device = {
.name = "Paradise Systems 5-PAK",
.internal_name = "p5pak",
.flags = DEVICE_ISA,
.local = ISAMEM_P5PAK_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = p5pak_config
};
static const device_config_t a6pak_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 64,
.file_filter = "",
.spinner = {
.min = 0,
.max = 576,
.step = 64
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 256,
.file_filter = "",
.spinner = {
.min = 64,
.max = 512,
.step = 64
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t a6pak_device = {
.name = "AST SixPakPlus",
.internal_name = "a6pak",
.flags = DEVICE_ISA,
.local = ISAMEM_A6PAK_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = a6pak_config
};
static const device_config_t ems5150_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 256,
.file_filter = "",
.spinner = {
.min = 0,
.max = 2048,
.step = 64
},
.selection = { { 0 } }
},
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = 0x0000 },
{ .description = "Board 1", .value = 0x0208 },
{ .description = "Board 2", .value = 0x020a },
{ .description = "Board 3", .value = 0x020c },
{ .description = "Board 4", .value = 0x020e },
{ .description = "" }
},
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t ems5150_device = {
.name = "Micro Mainframe EMS-5150(T)",
.internal_name = "ems5150",
.flags = DEVICE_ISA,
.local = ISAMEM_EMS5150_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = ems5150_config
};
static const device_config_t ev159_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 0,
.max = 3072,
.step = 512
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = {
.min = 0,
.max = 16128,
.step = 128
},
.selection = { { 0 } }
},
{
.name = "length",
.description = "Contiguous Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = {
.min = 0,
.max = 16384,
.step = 128
},
.selection = { { 0 } }
},
{
.name = "width",
.description = "I/O Width",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "8-bit", .value = 0 },
{ .description = "16-bit", .value = 1 },
{ .description = "" }
},
},
{
.name = "speed",
.description = "Transfer Speed",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "Standard (150ns)", .value = 0 },
{ .description = "High-Speed (120ns)", .value = 1 },
{ .description = "" }
}
},
{
.name = "ems",
.description = "EMS mode",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = 0 },
{ .description = "Enabled", .value = 1 },
{ .description = "" }
},
},
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0258,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "208H", .value = 0x0208 },
{ .description = "218H", .value = 0x0218 },
{ .description = "258H", .value = 0x0258 },
{ .description = "268H", .value = 0x0268 },
{ .description = "2A8H", .value = 0x02A8 },
{ .description = "2B8H", .value = 0x02B8 },
{ .description = "2E8H", .value = 0x02E8 },
{ .description = "" }
},
},
{
.name = "base2",
.description = "Address for > 2 MB",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0268,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "208H", .value = 0x0208 },
{ .description = "218H", .value = 0x0218 },
{ .description = "258H", .value = 0x0258 },
{ .description = "268H", .value = 0x0268 },
{ .description = "2A8H", .value = 0x02A8 },
{ .description = "2B8H", .value = 0x02B8 },
{ .description = "2E8H", .value = 0x02E8 },
{ .description = "" }
},
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t ev159_device = {
.name = "Everex EV-159 RAM 3000 Deluxe",
.internal_name = "ev159",
.flags = DEVICE_ISA,
.local = ISAMEM_EV159_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = ev159_config
};
static const device_config_t ev165a_config[] = {
// clang-format off
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 0,
.max = 2048,
.step = 512
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = {
.min = 0,
.max = 896,
.step = 128
},
.selection = { { 0 } }
},
{
.name = "length",
.description = "Contiguous Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = {
.min = 0,
.max = 16384,
.step = 128
},
.selection = { { 0 } }
},
{
.name = "ems",
.description = "EMS mode",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = 0 },
{ .description = "Enabled", .value = 1 },
{ .description = "" }
},
},
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0258,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "208H", .value = 0x0208 },
{ .description = "218H", .value = 0x0218 },
{ .description = "258H", .value = 0x0258 },
{ .description = "268H", .value = 0x0268 },
{ .description = "2A8H", .value = 0x02A8 },
{ .description = "2B8H", .value = 0x02B8 },
{ .description = "2E8H", .value = 0x02E8 },
{ .description = "" }
},
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t ev165a_device = {
.name = "Everex Magi Magic EV-165A",
.internal_name = "ev165a",
.flags = DEVICE_ISA,
.local = ISAMEM_EV165A_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = ev165a_config
};
static const device_config_t brxt_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0268,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "208H", .value = 0x0208 },
{ .description = "218H", .value = 0x0218 },
{ .description = "258H", .value = 0x0258 },
{ .description = "268H", .value = 0x0268 },
{ .description = "" }
},
},
{
.name = "frame",
.description = "Frame Address",
.type = CONFIG_HEX20,
.default_string = "",
.default_int = 0xD0000,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "D000H", .value = 0xD0000 },
{ .description = "E000H", .value = 0xE0000 },
{ .description = "" }
},
},
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 0,
.max = 2048,
.step = 512
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t brxt_device = {
.name = "BocaRAM/XT",
.internal_name = "brxt",
.flags = DEVICE_ISA,
.local = ISAMEM_BRXT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = brxt_config
};
#if defined(DEV_BRANCH) && defined(USE_ISAMEM_BRAT)
static const device_config_t brat_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0268,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "208H", .value = 0x0208 },
{ .description = "218H", .value = 0x0218 },
{ .description = "258H", .value = 0x0258 },
{ .description = "268H", .value = 0x0268 },
{ .description = "" }
},
},
{
.name = "frame",
.description = "Frame Address",
.type = CONFIG_HEX20,
.default_string = "",
.default_int = 0xD0000,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "D000H", .value = 0xD0000 },
{ .description = "E000H", .value = 0xE0000 },
{ .description = "" }
},
},
{
.name = "width",
.description = "I/O Width",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 8,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "8-bit", .value = 8 },
{ .description = "16-bit", .value = 16 },
{ .description = "" }
},
},
{
.name = "speed",
.description = "Transfer Speed",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "Standard", .value = 0 },
{ .description = "High-Speed", .value = 1 },
{ .description = "" }
}
},
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 512,
.file_filter = "",
.spinner = {
.min = 0,
.max = 4096,
.step = 512
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = {
.min = 0,
.max = 14336,
.step = 512
},
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t brat_device = {
.name = "BocaRAM/AT",
.internal_name = "brat",
.flags = DEVICE_ISA,
.local = ISAMEM_BRAT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = brat_config
};
#endif
static const device_config_t lotech_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0260,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "260H", .value = 0x0260 },
{ .description = "264H", .value = 0x0264 },
{ .description = "268H", .value = 0x0268 },
{ .description = "26CH", .value = 0x026C },
{ .description = "" }
},
},
{
.name = "frame",
.description = "Frame Address",
.type = CONFIG_HEX20,
.default_string = "",
.default_int = 0xe0000,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "C000H", .value = 0xC0000 },
{ .description = "D000H", .value = 0xD0000 },
{ .description = "E000H", .value = 0xE0000 },
{ .description = "" }
},
},
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 2048,
.file_filter = "",
.spinner = {
.min = 512,
.max = 4096,
.step = 512
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t lotech_device = {
.name = "Lo-tech EMS Board",
.internal_name = "lotechems",
.flags = DEVICE_ISA,
.local = ISAMEM_LOTECH_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = lotech_config
};
#if defined(DEV_BRANCH) && defined(USE_ISAMEM_RAMPAGE)
// TODO: Dual Paging support
// TODO: Conventional memory suppport
static const device_config_t rampage_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0218,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "208H", .value = 0x0208 },
{ .description = "218H", .value = 0x0218 },
{ .description = "258H", .value = 0x0258 },
{ .description = "268H", .value = 0x0268 },
{ .description = "2A8H", .value = 0x02A8 },
{ .description = "2B8H", .value = 0x02B8 },
{ .description = "2E8H", .value = 0x02E8 },
{ .description = "" }
},
},
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 256, /* Technically 128k, but banks 2-7 must be 256, headaches elsewise */
.file_filter = "",
.spinner = {
.min = 256,
.max = 2048,
.step = 256
},
.selection = { { 0 } }
},
{
.name = "start",
.description = "Start Address",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 640,
.file_filter = "",
.spinner = {
.min = 0,
.max = 640,
.step = 64
},
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t rampage_device = {
.name = "AST RAMpage/XT",
.internal_name = "rampage",
.flags = DEVICE_ISA,
.local = ISAMEM_RAMPAGEXT_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = rampage_config
};
#endif
#if defined(DEV_BRANCH) && defined(USE_ISAMEM_IAB)
static const device_config_t iab_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = "",
.default_int = 0x0258,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "208H", .value = 0x0208 },
{ .description = "218H", .value = 0x0218 },
{ .description = "258H", .value = 0x0258 },
{ .description = "268H", .value = 0x0268 },
{ .description = "2A8H", .value = 0x02A8 },
{ .description = "2B8H", .value = 0x02B8 },
{ .description = "2E8H", .value = 0x02E8 },
{ .description = "" }
},
},
{
.name = "frame",
.description = "Frame Address",
.type = CONFIG_HEX20,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = 0x00000 },
{ .description = "C000H", .value = 0xC0000 },
{ .description = "D000H", .value = 0xD0000 },
{ .description = "E000H", .value = 0xE0000 },
{ .description = "" }
},
},
{
.name = "width",
.description = "I/O Width",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 8,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "8-bit", .value = 8 },
{ .description = "16-bit", .value = 16 },
{ .description = "" }
},
},
{
.name = "speed",
.description = "Transfer Speed",
.type = CONFIG_SELECTION,
.default_string = "",
.default_int = 0,
.file_filter = "",
.spinner = { 0 },
.selection = {
{ .description = "Standard", .value = 0 },
{ .description = "High-Speed", .value = 1 },
{ .description = "" }
}
},
{
.name = "size",
.description = "Memory Size",
.type = CONFIG_SPINNER,
.default_string = "",
.default_int = 128,
.file_filter = "",
.spinner = {
.min = 0,
.max = 8192,
.step = 128
},
.selection = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
static const device_t iab_device = {
.name = "Intel AboveBoard",
.internal_name = "iab",
.flags = DEVICE_ISA,
.local = ISAMEM_ABOVEBOARD_CARD,
.init = isamem_init,
.close = isamem_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = iab_config
};
#endif
static const device_t isa_none_device = {
.name = "None",
.internal_name = "none",
.flags = 0,
.local = 0,
.init = NULL,
.close = NULL,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
static const struct {
const device_t *dev;
} boards[] = {
// clang-format off
{ &isa_none_device },
// XT Ram Expansion Cards
{ &ibmxt_32k_device },
{ &ibmxt_64k_device },
{ &ibmxt_device },
{ &genericxt_device },
{ &msramcard_device },
{ &mssystemcard_device },
// AT RAM Expansion Cards
{ &ibmat_128k_device },
{ &ibmat_device },
{ &genericat_device },
// EMS Cards
{ &p5pak_device },
{ &a6pak_device },
{ &ems5150_device },
{ &ev159_device },
{ &ev165a_device },
{ &brxt_device },
#if defined(DEV_BRANCH) && defined(USE_ISAMEM_BRAT)
{ &brat_device },
#endif
#if defined(DEV_BRANCH) && defined(USE_ISAMEM_RAMPAGE)
{ &rampage_device },
#endif
#if defined(DEV_BRANCH) && defined(USE_ISAMEM_IAB)
{ &iab_device },
#endif
{ &lotech_device },
{ NULL }
// clang-format on
};
void
isamem_reset(void)
{
int k;
/* We explicitly set to zero here or bad things happen */
isa_mem_size = 0;
for (uint8_t i = 0; i < ISAMEM_MAX; i++) {
k = isamem_type[i];
if (k == 0)
continue;
/* Add the instance to the system. */
device_add_inst(boards[k].dev, i + 1);
}
}
const char *
isamem_get_name(int board)
{
if (boards[board].dev == NULL)
return (NULL);
return (boards[board].dev->name);
}
const char *
isamem_get_internal_name(int board)
{
return device_get_internal_name(boards[board].dev);
}
int
isamem_get_from_internal_name(const char *s)
{
int c = 0;
while (boards[c].dev != NULL) {
if (!strcmp(boards[c].dev->internal_name, s))
return c;
c++;
}
/* Not found. */
return 0;
}
const device_t *
isamem_get_device(int board)
{
/* Add the instance to the system. */
return boards[board].dev;
}