SM(S)C FDC37C93x Super I/O chip rewrite, add the Acer V62x, and un-dev-branch the V-Tech Laser XT machines.

This commit is contained in:
OBattler
2025-05-05 05:11:55 +02:00
parent dca7ed737c
commit 018bbfae43
17 changed files with 1810 additions and 666 deletions

View File

@@ -1,6 +1,7 @@
/*This is the chipset used in the LaserXT series model*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <86box/86box.h>
@@ -21,125 +22,411 @@
#include <86box/keyboard.h>
#include <86box/plat_unused.h>
static int laserxt_emspage[4];
static int laserxt_emscontrol[4];
static mem_mapping_t laserxt_ems_mapping[4];
static int laserxt_ems_baseaddr_index = 0;
static int laserxt_is_lxt3 = 0;
#define EMS_TOTAL_MAX 0x00100000
static uint32_t
get_laserxt_ems_addr(uint32_t addr)
typedef struct
{
if (laserxt_emspage[(addr >> 14) & 3] & 0x80) {
addr = (!laserxt_is_lxt3 ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)) + ((laserxt_emspage[(addr >> 14) & 3] & 0x0F) << 14) + ((laserxt_emspage[(addr >> 14) & 3] & 0x40) << 12) + (addr & 0x3FFF);
}
uint8_t page;
uint8_t ctrl;
return addr;
uint32_t phys;
uint32_t virt;
mem_mapping_t mapping;
uint8_t *ram;
void *parent;
} lxt_ems_t;
typedef struct
{
int ems_base_idx;
lxt_ems_t ems[4];
uint16_t io_base;
uint32_t base;
uint32_t mem_size;
uint8_t *ram;
void *parent;
} lxt_ems_board_t;
typedef struct
{
int is_lxt3;
lxt_ems_board_t *ems_boards[2];
} lxt_t;
static void
ems_update_virt(lxt_ems_t *dev, uint8_t new_page)
{
lxt_ems_board_t *board = (lxt_ems_board_t *) dev->parent;
lxt_t *lxt = (lxt_t *) board->parent;
dev->page = new_page;
if (new_page & 0x80) {
if (lxt->is_lxt3) {
/* Point invalid pages at 1 MB which is outside the maximum. */
if ((new_page & 0x7f) >= 0x40)
dev->virt = EMS_TOTAL_MAX;
else
dev->virt = ((new_page & 0x7f) << 14);
} else
dev->virt = ((new_page & 0x0f) << 14) + ((new_page & 0x40) << 12);
if (dev->virt >= board->mem_size)
dev->virt = EMS_TOTAL_MAX;
} else
dev->virt = EMS_TOTAL_MAX;
dev->ram = board->ram + dev->virt;
if ((new_page & 0x80) && (dev->virt != EMS_TOTAL_MAX)) {
mem_mapping_enable(&dev->mapping);
mem_mapping_set_exec(&dev->mapping, dev->ram);
mem_mapping_set_p(&dev->mapping, dev->ram);
} else
mem_mapping_disable(&dev->mapping);
flushmmucache();
}
static void
laserxt_write(uint16_t port, uint8_t val, UNUSED(void *priv))
lxt_ems_out(uint16_t port, uint8_t val, void *priv)
{
uint32_t paddr;
uint32_t vaddr;
switch (port) {
case 0x0208:
case 0x4208:
case 0x8208:
case 0xC208:
laserxt_emspage[port >> 14] = val;
paddr = 0xC0000 + (port & 0xC000) + (((laserxt_ems_baseaddr_index + (4 - (port >> 14))) & 0x0C) << 14);
if (val & 0x80) {
mem_mapping_enable(&laserxt_ems_mapping[port >> 14]);
vaddr = get_laserxt_ems_addr(paddr);
mem_mapping_set_exec(&laserxt_ems_mapping[port >> 14], ram + vaddr);
} else {
mem_mapping_disable(&laserxt_ems_mapping[port >> 14]);
}
flushmmucache();
break;
case 0x0209:
case 0x4209:
case 0x8209:
case 0xC209:
laserxt_emscontrol[port >> 14] = val;
laserxt_ems_baseaddr_index = 0;
lxt_ems_board_t *dev = (lxt_ems_board_t *) priv;
uint8_t reg = port >> 14;
uint32_t saddrs[8] = { 0xc4000, 0xc8000, 0xcc000, 0xd0000,
0xd4000, 0xd8000, 0xdc000, 0xe0000 };
uint32_t saddr;
if (port & 0x0001) {
dev->ems[reg].ctrl = val;
if (reg < 0x03) {
dev->ems_base_idx = (dev->ems_base_idx & ~(0x04 >> (2 - reg))) |
((dev->ems[reg].ctrl & 0x80) >> (7 - reg));
saddr = saddrs[dev->ems_base_idx];
for (uint8_t i = 0; i < 4; i++) {
laserxt_ems_baseaddr_index |= (laserxt_emscontrol[i] & 0x80) >> (7 - i);
uint32_t base = saddr + (i * 0x4000);
mem_mapping_set_addr(&dev->ems[i].mapping, base, 0x4000);
if (!(dev->ems[i].page & 0x80) || (dev->ems[i].virt == EMS_TOTAL_MAX))
mem_mapping_disable(&dev->ems[i].mapping);
}
}
mem_mapping_set_addr(&laserxt_ems_mapping[0], 0xC0000 + (((laserxt_ems_baseaddr_index + 4) & 0x0C) << 14), 0x4000);
mem_mapping_set_addr(&laserxt_ems_mapping[1], 0xC4000 + (((laserxt_ems_baseaddr_index + 3) & 0x0C) << 14), 0x4000);
mem_mapping_set_addr(&laserxt_ems_mapping[2], 0xC8000 + (((laserxt_ems_baseaddr_index + 2) & 0x0C) << 14), 0x4000);
mem_mapping_set_addr(&laserxt_ems_mapping[3], 0xCC000 + (((laserxt_ems_baseaddr_index + 1) & 0x0C) << 14), 0x4000);
flushmmucache();
break;
default:
break;
flushmmucache();
} else if (!(port & 0x0001)) {
dev->ems[reg].page = val;
ems_update_virt(&dev->ems[reg], val);
}
}
static uint8_t
laserxt_read(uint16_t port, UNUSED(void *priv))
lxt_ems_in(uint16_t port, void *priv)
{
switch (port) {
case 0x0208:
case 0x4208:
case 0x8208:
case 0xC208:
return laserxt_emspage[port >> 14];
case 0x0209:
case 0x4209:
case 0x8209:
case 0xC209:
return laserxt_emscontrol[port >> 14];
lxt_ems_board_t *dev = (lxt_ems_board_t *) priv;
uint8_t reg = port >> 14;
uint8_t ret = 0xff;
default:
break;
}
return 0xff;
if (port & 0x0001)
ret = dev->ems[reg].ctrl;
else
ret = dev->ems[reg].page;
return ret;
}
static void
mem_write_laserxtems(uint32_t addr, uint8_t val, UNUSED(void *priv))
lxt_ems_write(uint32_t addr, uint8_t val, void *priv)
{
addr = get_laserxt_ems_addr(addr);
if (addr < (mem_size << 10))
ram[addr] = val;
uint8_t *mem = (uint8_t *) priv;
mem[addr & 0x3fff] = val;
}
static uint8_t
mem_read_laserxtems(uint32_t addr, UNUSED(void *priv))
lxt_ems_read(uint32_t addr, void *priv)
{
uint8_t val = 0xFF;
addr = get_laserxt_ems_addr(addr);
if (addr < (mem_size << 10))
val = ram[addr];
return val;
uint8_t *mem = (uint8_t *) priv;
uint8_t ret = 0xff;
ret = mem[addr & 0x3fff];
return ret;
}
static lxt_ems_board_t *
lxt_ems_init(lxt_t *parent, int en, uint16_t io, uint32_t mem)
{
lxt_ems_board_t *dev = (lxt_ems_board_t *) calloc(1, sizeof(lxt_ems_board_t));
if (en) {
dev->parent = parent;
if (io != 0x0000) {
io_sethandler(io , 0x0002, lxt_ems_in, NULL, NULL, lxt_ems_out, NULL, NULL, dev);
io_sethandler(io | 0x4000, 0x0002, lxt_ems_in, NULL, NULL, lxt_ems_out, NULL, NULL, dev);
io_sethandler(io | 0x8000, 0x0002, lxt_ems_in, NULL, NULL, lxt_ems_out, NULL, NULL, dev);
io_sethandler(io | 0xc000, 0x0002, lxt_ems_in, NULL, NULL, lxt_ems_out, NULL, NULL, dev);
}
dev->ram = (uint8_t *) calloc(mem, sizeof(uint8_t));
dev->mem_size = mem;
for (uint8_t i = 0; i < 4; i++) {
uint8_t *ptr = dev->ram + (i << 14);
mem_mapping_add(&dev->ems[i].mapping, 0xe0000 + (i << 14), 0x4000,
lxt_ems_read, NULL, NULL,
lxt_ems_write, NULL, NULL,
ptr, 0, ptr);
mem_mapping_disable(&dev->ems[i].mapping);
dev->ems[i].page = 0x7f;
dev->ems[i].ctrl = (i == 3) ? 0x00 : 0x80;
dev->ems[i].parent = dev;
ems_update_virt(&(dev->ems[i]), dev->ems[i].page);
}
}
return dev;
}
static void
laserxt_init(int is_lxt3)
lxt_close(void *priv)
{
if (mem_size > 640) {
io_sethandler(0x0208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL);
io_sethandler(0x4208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL);
io_sethandler(0x8208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL);
io_sethandler(0xc208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL);
mem_mapping_set_addr(&ram_low_mapping, 0, !is_lxt3 ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10));
lxt_t *dev = (lxt_t *) priv;
int ems_boards = (1 - dev->is_lxt3) + 1;
for (int i = 0; i < ems_boards; i++)
if (dev->ems_boards[i] != NULL) {
if (dev->ems_boards[i]->ram != NULL)
free(dev->ems_boards[i]->ram);
free(dev->ems_boards[i]);
}
free(dev);
}
static void *
lxt_init(const device_t *info)
{
lxt_t * dev = (lxt_t *) calloc(1, sizeof(lxt_t));
int ems_boards = (1 - info->local) + 1;
int ems_en[2] = { 0 };
uint16_t ems_io[2] = { 0 };
uint32_t ems_mem[2] = { 0 };
char conf_str[512] = { 0 };
dev->is_lxt3 = info->local;
for (int i = 0; i < ems_boards; i++) {
sprintf(conf_str, "ems_%i_enable", i + 1);
ems_en[i] = device_get_config_int(conf_str);
sprintf(conf_str, "ems_%i_base", i + 1);
ems_io[i] = device_get_config_hex16(conf_str);
sprintf(conf_str, "ems_%i_mem_size", i + 1);
ems_mem[i] = device_get_config_int(conf_str) << 10;
dev->ems_boards[i] = lxt_ems_init(dev, ems_en[i], ems_io[i], ems_mem[i]);
}
for (uint8_t i = 0; i < 4; i++) {
laserxt_emspage[i] = 0x7F;
laserxt_emscontrol[i] = (i == 3) ? 0x00 : 0x80;
mem_mapping_add(&laserxt_ems_mapping[i], 0xE0000 + (i << 14), 0x4000, mem_read_laserxtems, NULL, NULL, mem_write_laserxtems, NULL, NULL, ram + 0xA0000 + (i << 14), 0, NULL);
mem_mapping_disable(&laserxt_ems_mapping[i]);
}
mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
laserxt_is_lxt3 = is_lxt3;
return dev;
}
static const device_config_t laserxt_config[] = {
{
.name = "ems_1_base",
.description = "EMS 1 Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = 0 },
{ .description = "0x208", .value = 0x208 },
{ .description = "0x218", .value = 0x218 },
{ .description = "0x258", .value = 0x258 },
{ .description = "0x268", .value = 0x268 },
{ .description = "0x2A8", .value = 0x2a8 },
{ .description = "0x2B8", .value = 0x2b8 },
{ .description = "0x2E8", .value = 0x2e8 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "ems_2_base",
.description = "EMS 2 Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = 0 },
{ .description = "0x208", .value = 0x208 },
{ .description = "0x218", .value = 0x218 },
{ .description = "0x258", .value = 0x258 },
{ .description = "0x268", .value = 0x268 },
{ .description = "0x2A8", .value = 0x2a8 },
{ .description = "0x2B8", .value = 0x2b8 },
{ .description = "0x2E8", .value = 0x2e8 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "ems_1_mem_size",
.description = "EMS 1 Memory Size",
.type = CONFIG_SPINNER,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = {
.min = 0,
.max = 512,
.step = 32
},
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "ems_2_mem_size",
.description = "EMS 2 Memory Size",
.type = CONFIG_SPINNER,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = {
.min = 0,
.max = 512,
.step = 32
},
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "ems_1_enable",
.description = "Enable EMS 1",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "ems_2_enable",
.description = "Enable EMS 2",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
const device_t laserxt_device = {
.name = "VTech Laser Turbo XT",
.internal_name = "laserxt",
.flags = 0,
.local = 0,
.init = lxt_init,
.close = lxt_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = laserxt_config
};
static const device_config_t lxt3_config[] = {
{
.name = "ems_1_base",
.description = "EMS Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = 0 },
{ .description = "0x208", .value = 0x208 },
{ .description = "0x218", .value = 0x218 },
{ .description = "0x258", .value = 0x258 },
{ .description = "0x268", .value = 0x268 },
{ .description = "0x2A8", .value = 0x2a8 },
{ .description = "0x2B8", .value = 0x2b8 },
{ .description = "0x2E8", .value = 0x2e8 },
{ .description = "" }
},
.bios = { { 0 } }
},
{
.name = "ems_1_mem_size",
.description = "EMS Memory Size",
.type = CONFIG_SPINNER,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = {
.min = 0,
.max = 1024,
.step = 32
},
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "ems_1_enable",
.description = "Enable EMS",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
const device_t lxt3_device = {
.name = "VTech Laser Turbo XT",
.internal_name = "laserxt",
.flags = 0,
.local = 1,
.init = lxt_init,
.close = lxt_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = lxt3_config
};
static void
machine_xt_laserxt_common_init(const machine_t *model,int is_lxt3)
{
@@ -153,7 +440,7 @@ machine_xt_laserxt_common_init(const machine_t *model,int is_lxt3)
nmi_init();
standalone_gameport_type = &gameport_device;
laserxt_init(is_lxt3);
device_add(is_lxt3 ? &lxt3_device : &laserxt_device);
device_add(&keyboard_xt_lxt3_device);
}