NEAT: More fixes, closes #5145.

This commit is contained in:
OBattler
2025-01-15 04:30:59 +01:00
parent aa34357083
commit 6d1d6d8830

View File

@@ -231,6 +231,8 @@ typedef struct neat_t {
uint16_t ems_size; /* EMS size in KB */
uint16_t ems_pages; /* EMS size in pages */
uint32_t remap_base;
ram_page_t ems[EMS_MAXPAGE]; /* EMS page registers */
ram_page_t shadow[32]; /* Shadow RAM pages */
} neat_t;
@@ -238,6 +240,9 @@ typedef struct neat_t {
static uint8_t defaults[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00,
0x00, 0x00, 0xa0, 0x63, 0x10, 0x00, 0x00, 0x12 };
static uint8_t masks[4] = { RB10_P0EXT, RB10_P1EXT, RB10_P2EXT, RB10_P3EXT };
static uint8_t shifts[4] = { RB10_P0EXT_SH, RB10_P1EXT_SH, RB10_P2EXT_SH, RB10_P3EXT_SH };
#ifdef ENABLE_NEAT_LOG
int neat_do_log = ENABLE_NEAT_LOG;
@@ -262,10 +267,17 @@ ems_readb(uint32_t addr, void *priv)
{
ram_page_t *dev = (ram_page_t *) priv;
uint8_t ret = 0xff;
#ifdef ENABLE_NEAT_LOG
uint32_t old = addr;
#endif
/* Grab the data. */
ret = *(uint8_t *) &(ram[addr - dev->virt_base + dev->phys_base]);
addr = addr - dev->virt_base + dev->phys_base;
if (addr < (mem_size << 10))
ret = *(uint8_t *) &(ram[addr]);
neat_log("[R08] %08X -> %08X (%08X): ret = %02X\n", old, addr, (mem_size << 10), ret);
return ret;
}
@@ -275,10 +287,17 @@ ems_readw(uint32_t addr, void *priv)
{
ram_page_t *dev = (ram_page_t *) priv;
uint16_t ret = 0xffff;
#ifdef ENABLE_NEAT_LOG
uint32_t old = addr;
#endif
/* Grab the data. */
ret = *(uint16_t *) &(ram[addr - dev->virt_base + dev->phys_base]);
addr = addr - dev->virt_base + dev->phys_base;
if (addr < (mem_size << 10))
ret = *(uint16_t *) &(ram[addr]);
neat_log("[R16] %08X -> %08X (%08X): ret = %04X\n", old, addr, (mem_size << 10), ret);
return ret;
}
@@ -287,9 +306,16 @@ static void
ems_writeb(uint32_t addr, uint8_t val, void *priv)
{
ram_page_t *dev = (ram_page_t *) priv;
#ifdef ENABLE_NEAT_LOG
uint32_t old = addr;
#endif
/* Write the data. */
*(uint8_t *) &(ram[addr - dev->virt_base + dev->phys_base]) = val;
addr = addr - dev->virt_base + dev->phys_base;
neat_log("[W08] %08X -> %08X (%08X): val = %02X\n", old, addr, (mem_size << 10), val);
if (addr < (mem_size << 10))
*(uint8_t *) &(ram[addr]) = val;
}
/* Write one word to paged RAM. */
@@ -297,9 +323,16 @@ static void
ems_writew(uint32_t addr, uint16_t val, void *priv)
{
ram_page_t *dev = (ram_page_t *) priv;
#ifdef ENABLE_NEAT_LOG
uint32_t old = addr;
#endif
/* Write the data. */
*(uint16_t *) &(ram[addr - dev->virt_base + dev->phys_base]) = val;
addr = addr - dev->virt_base + dev->phys_base;
neat_log("[W16] %08X -> %08X (%08X): val = %04X\n", old, addr, (mem_size << 10), val);
if (addr < (mem_size << 10))
*(uint16_t *) &(ram[addr]) = val;
}
static void
@@ -379,10 +412,11 @@ shadow_recalc(neat_t *dev)
static void
ems_recalc(neat_t *dev, ram_page_t *ems)
{
uint32_t page = ems->phys_base / EMS_PGSIZE;
uint32_t page = ems->phys_base / EMS_PGSIZE;
if ((dev->regs[REG_RB7] & RB7_EMSEN) && ems->enabled &&
(page >= 0x40) && (page < (0x40 + dev->ems_pages))) {
neat_log("ems_recalc(): %08X, %04X, %04X\n", ems->virt_base, page, dev->ems_pages);
if ((dev->regs[REG_RB7] & RB7_EMSEN) && ems->enabled && (page < dev->ems_pages)) {
neat_log("ems_recalc(): %08X-%08X -> %08X-%08X\n",
ems->virt_base, ems->virt_base + EMS_PGSIZE - 1,
ems->phys_base, ems->phys_base + EMS_PGSIZE - 1);
@@ -405,14 +439,20 @@ ems_recalc(neat_t *dev, ram_page_t *ems)
if ((ems->virt_base >= 0x00080000) && (ems->virt_base < 0x00100000))
neat_mem_update_state(dev, ems->virt_base, EMS_PGSIZE, 0x00, RAM_FMASK_EMS);
}
flushmmucache_nopc();
}
static void
ems_write(uint16_t port, uint8_t val, void *priv)
{
neat_t *dev = (neat_t *) priv;
neat_t *dev = (neat_t *) priv;
ram_page_t *ems;
int vpage;
int8_t old_enabled;
uint32_t old_phys_base;
int8_t new_enabled;
uint32_t new_phys_base;
#if NEAT_DEBUG > 1
neat_log("NEAT: ems_write(%04x, %02x)\n", port, val);
@@ -422,12 +462,29 @@ ems_write(uint16_t port, uint8_t val, void *priv)
vpage = (port / EMS_PGSIZE);
ems = &dev->ems[vpage];
neat_log("Port: %04X, val: %02X\n", port, val);
switch (port & 0x000f) {
case 0x0008:
case 0x0009:
ems->enabled = !!(val & 0x80);
ems->phys_base = (ems->phys_base & 0xffe00000) | ((val & 0x7f) * EMS_PGSIZE);
ems_recalc(dev, ems);
old_enabled = ems->enabled;
old_phys_base = ems->phys_base;
new_enabled = !!(val & 0x80);
new_phys_base = (ems->phys_base & 0xffe00000) | ((val & 0x7f) * EMS_PGSIZE);
if ((old_enabled != new_enabled) || (old_phys_base != new_phys_base)) {
if (old_enabled && (old_enabled == new_enabled)) {
ems->enabled = 0;
ems_recalc(dev, ems);
}
ems->enabled = !!(val & 0x80);
if (old_phys_base != new_phys_base)
ems->phys_base = (ems->phys_base & 0xffe00000) | ((val & 0x7f) * EMS_PGSIZE);
ems_recalc(dev, ems);
}
break;
default:
break;
@@ -454,6 +511,8 @@ ems_read(uint16_t port, void *priv)
break;
}
neat_log("Port: %04X, ret: %02X\n", port, ret);
#if NEAT_DEBUG > 1
neat_log("NEAT: ems_read(%04x) = %02x\n", port, ret);
#endif
@@ -462,20 +521,76 @@ ems_read(uint16_t port, void *priv)
}
static void
ems_update(neat_t *dev, int en)
ems_recalc_all(neat_t *dev)
{
for (uint8_t i = 0; i < EMS_MAXPAGE; i++)
ems_recalc(dev, &(dev->ems[i]));
}
static void
ems_update_virt_base(neat_t *dev)
{
for (uint8_t i = 0; i < EMS_MAXPAGE; i++)
dev->ems[i].virt_base = dev->ems_frame + (i * EMS_PGSIZE);
}
static void
ems_remove_handlers(neat_t *dev)
{
for (uint8_t i = 0; i < EMS_MAXPAGE; i++) {
neat_log("Removing I/O handler at %04X-%04X\n",
dev->ems_base + (i * EMS_PGSIZE), dev->ems_base + (i * EMS_PGSIZE) + 1);
/* Clean up any previous I/O port handler. */
io_removehandler(dev->ems_base + (i * EMS_PGSIZE), 2,
ems_read, NULL, NULL, ems_write, NULL, NULL, dev);
}
}
static void
ems_set_handlers(neat_t *dev)
{
for (uint8_t i = 0; i < EMS_MAXPAGE; i++) {
neat_log("Setting up I/O handler at %04X-%04X\n",
dev->ems_base + (i * EMS_PGSIZE), dev->ems_base + (i * EMS_PGSIZE) + 1);
/* Set up an I/O port handler. */
io_handler(en, dev->ems_base + (i * EMS_PGSIZE), 2,
ems_read, NULL, NULL, ems_write, NULL, NULL, dev);
if (en)
dev->ems[i].virt_base = dev->ems_frame + (i * EMS_PGSIZE);
ems_recalc(dev, &(dev->ems[i]));
io_sethandler(dev->ems_base + (i * EMS_PGSIZE), 2,
ems_read, NULL, NULL, ems_write, NULL, NULL, dev);
}
flushmmucache_nopc();
ems_recalc_all(dev);
}
static void
remap_update(neat_t *dev, uint8_t val)
{
if (dev->regs[REG_RB7] & RB7_UMAREL) {
mem_remap_top_ex(0, (dev->remap_base >= 1024) ? dev->remap_base : 1024);
neat_log("0 kB at %08X\n", ((dev->remap_base >= 1024) ? dev->remap_base : 1024) << 10);
}
if (val & RB7_EMSEN)
dev->remap_base = mem_size - dev->ems_size;
else
dev->remap_base = mem_size;
neat_log("Total contiguous memory now: %i kB\n", dev->remap_base);
if (dev->remap_base >= 640)
mem_mapping_set_addr(&ram_low_mapping, 0x00000000, 0x000a0000);
else
mem_mapping_set_addr(&ram_low_mapping, 0x00000000, dev->remap_base << 10);
if (dev->remap_base > 1024)
mem_mapping_set_addr(&ram_high_mapping, 0x00100000, (dev->remap_base << 10) - 0x00100000);
else
mem_mapping_disable(&ram_high_mapping);
if (val & RB7_UMAREL) {
mem_remap_top_ex(384, (dev->remap_base >= 1024) ? dev->remap_base : 1024);
neat_log("384 kB at %08X\n", ((dev->remap_base >= 1024) ? dev->remap_base : 1024) << 10);
}
/* Yes, this has to be done on every step because mem_remap_top_ex() reenables it. */
mem_mapping_disable(&ram_mid_mapping);
}
static void
@@ -590,20 +705,21 @@ neat_write(uint16_t port, uint8_t val, void *priv)
case REG_RB7:
val &= RB7_MASK;
*reg = val;
if (xval & (RB7_EMSEN | RB7_UMAREL))
remap_update(dev, val);
dev->regs[REG_RB7] = val;
if (xval & RB7_EMSEN)
ems_remove_handlers(dev);
if ((xval & RB7_EMSEN) && (val & RB7_EMSEN))
ems_set_handlers(dev);
#if NEAT_DEBUG > 1
neat_log("NEAT: RB7=%02x(%02x)\n", val, *reg);
#endif
if (xval & RB7_EMSEN)
ems_update(dev, !!(val & RB7_EMSEN));
if (xval & RB7_UMAREL) {
if (val & RB7_UMAREL)
mem_remap_top(384);
else
mem_remap_top(0);
}
break;
case REG_RB8:
@@ -621,18 +737,20 @@ neat_write(uint16_t port, uint8_t val, void *priv)
neat_log("NEAT: RB9=%02x(%02x)\n", val, *reg);
#endif
ems_update(dev, 0);
ems_remove_handlers(dev);
/* Get configured I/O address. */
j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH;
dev->ems_base = 0x0208 + (0x10 * j);
j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH;
dev->ems_base = 0x0208 + (0x10 * j);
/* Get configured frame address. */
j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH;
dev->ems_frame = 0xc0000 + (EMS_PGSIZE * j);
ems_update_virt_base(dev);
if (dev->regs[REG_RB7] & RB7_EMSEN)
ems_update(dev, 1);
ems_set_handlers(dev);
break;
case REG_RB10:
@@ -642,18 +760,32 @@ neat_write(uint16_t port, uint8_t val, void *priv)
neat_log("NEAT: RB10=%02x(%02x)\n", val, *reg);
#endif
dev->ems[3].phys_base = (dev->ems[3].phys_base & 0x001fffff) |
(((val & RB10_P3EXT) >> RB10_P3EXT_SH) << 21);
dev->ems[2].phys_base = (dev->ems[2].phys_base & 0x001fffff) |
(((val & RB10_P2EXT) >> RB10_P2EXT_SH) << 21);
dev->ems[1].phys_base = (dev->ems[1].phys_base & 0x001fffff) |
(((val & RB10_P1EXT) >> RB10_P1EXT_SH) << 21);
dev->ems[0].phys_base = (dev->ems[0].phys_base & 0x001fffff) |
(((val & RB10_P0EXT) >> RB10_P0EXT_SH) << 21);
for (uint8_t i = 0; i < EMS_MAXPAGE; i++) {
ram_page_t *ems = &(dev->ems[i]);
uint32_t old_phys_base = ems->phys_base & 0xffe00000;
uint32_t new_phys_base = (((val & masks[i]) >> shifts[i]) << 21);
if (dev->regs[REG_RB7] & RB7_EMSEN)
for (i = 0; i < EMS_MAXPAGE; i++)
ems_recalc(dev, &dev->ems[i]);
if (new_phys_base != old_phys_base) {
int8_t old_enabled = ems->enabled;
if ((dev->regs[REG_RB7] & RB7_EMSEN) && old_enabled) {
ems->enabled = 0;
ems_recalc(dev, &(dev->ems[i]));
}
ems->phys_base = ems->phys_base - old_phys_base + new_phys_base;
if ((dev->regs[REG_RB7] & RB7_EMSEN) && old_enabled) {
ems->enabled = old_enabled;
ems_recalc(dev, &(dev->ems[i]));
}
}
}
neat_log("%08X, %08X, %08X, %08X\n",
dev->ems[0].phys_base, dev->ems[1].phys_base,
dev->ems[2].phys_base, dev->ems[3].phys_base);
break;
case REG_RB12:
@@ -680,15 +812,12 @@ neat_write(uint16_t port, uint8_t val, void *priv)
default:
break;
}
dev->ems_pages = (dev->ems_size << 10) / EMS_PGSIZE;
if (dev->regs[REG_RB7] & RB7_EMSEN)
for (i = 0; i < EMS_MAXPAGE; i++)
ems_recalc(dev, &dev->ems[i]);
if (dev->regs[REG_RB7] & RB7_EMSEN) {
neat_log("NEAT: EMS %iKB (%i pages)\n",
dev->ems_size, dev->ems_pages);
remap_update(dev, dev->regs[REG_RB7]);
neat_log("NEAT: EMS %iKB\n",
dev->ems_size);
}
mem_a20_key = val & RB12_GA20;
@@ -756,12 +885,17 @@ neat_init(UNUSED(const device_t *info))
memset(dev, 0x00, sizeof(neat_t));
/* Get configured I/O address. */
j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH;
dev->ems_base = 0x0208 + (0x10 * j);
j = (dev->regs[REG_RB9] & RB9_BASE) >> RB9_BASE_SH;
dev->ems_base = 0x0208 + (0x10 * j);
/* Get configured frame address. */
j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH;
dev->ems_frame = 0xc0000 + (EMS_PGSIZE * j);
j = (dev->regs[REG_RB9] & RB9_FRAME) >> RB9_FRAME_SH;
dev->ems_frame = 0xc0000 + (EMS_PGSIZE * j);
ems_update_virt_base(dev);
dev->ems_pages = (mem_size << 10) / EMS_PGSIZE;
dev->remap_base = mem_size;
mem_mapping_disable(&ram_mid_mapping);
@@ -773,10 +907,10 @@ neat_init(UNUSED(const device_t *info))
for (uint8_t i = 0; i < EMS_MAXPAGE; i++) {
/* Create and initialize a page mapping. */
mem_mapping_add(&dev->ems[i].mapping,
dev->ems_frame + (EMS_PGSIZE * i), EMS_PGSIZE,
0x00000000, 0x00000000,
ems_readb, ems_readw, NULL,
ems_writeb, ems_writew, NULL,
ram, MEM_MAPPING_INTERNAL,
ram + dev->ems[i].virt_base, MEM_MAPPING_INTERNAL,
&(dev->ems[i]));
/* Disable for now. */