Vastly improve the ALi M1409 emulation (all of shadow RAM now work, as does bus speed and external cache setting), and fix the "Writing unimplemented Cyrix register FF" error as well.

This commit is contained in:
OBattler
2025-05-29 09:45:49 +02:00
parent 0e972400b4
commit 25f0a26ea1
2 changed files with 210 additions and 64 deletions

View File

@@ -61,91 +61,238 @@ ali1409_log(const char *fmt, ...)
#endif
typedef struct ali_1409_t {
uint8_t is_g;
uint8_t index;
uint8_t cfg_locked;
uint8_t reg_57h;
uint8_t regs[256];
uint8_t shadow[4];
uint8_t last_reg;
} ali1409_t;
/*
This here is because from the two BIOS'es I used to reverse engineer this,
it is unclear which of the two interpretations of the shadow RAM register
operation is correct.
The 16 kB interpretation appears to work fine right now but it may be wrong,
so I left the 32 kB interpretation in as well.
*/
#ifdef INTERPRETATION_32KB
#define SHADOW_SIZE 0x00008000
#else
#define SHADOW_SIZE 0x00004000
#endif
static void
ali1409_shadow_recalc(ali1409_t *dev)
{
uint32_t base = 0x000c0000;
for (uint8_t i = 0; i < 4; i++) {
uint8_t reg = 0x08 + i;
#ifdef INTERPRETATION_32KB
for (uint8_t j = 0; j < 4; j += 2) {
uint8_t mask = (0x03 << j);
#else
for (uint8_t j = 0; j < 4; j++) {
uint8_t mask = (0x01 << j);
#endif
uint8_t r_on = dev->regs[reg] & 0x10;
uint8_t w_on = dev->regs[reg] & 0x20;
uint8_t val = dev->regs[reg] & mask;
uint8_t xor = (dev->shadow[i] ^ dev->regs[reg]) & (mask | 0x30);
int read = r_on ? MEM_READ_INTERNAL : MEM_READ_EXTANY;
int write = w_on ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTANY;
if (xor) {
#ifdef INTERPRETATION_32KB
switch (val >> j) {
case 0x00:
mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
break;
case 0x01:
mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | write);
break;
case 0x02:
mem_set_mem_state_both(base, SHADOW_SIZE, read | write);
break;
case 0x03:
mem_set_mem_state_both(base, SHADOW_SIZE, read | MEM_WRITE_EXTANY);
break;
}
#else
switch (val >> j) {
case 0x00:
mem_set_mem_state_both(base, SHADOW_SIZE, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
break;
case 0x01:
mem_set_mem_state_both(base, SHADOW_SIZE, read | write);
break;
}
#endif
}
base += SHADOW_SIZE;
}
dev->shadow[i] = dev->regs[reg];
}
flushmmucache_nopc();
}
static void
ali1409_write(uint16_t addr, uint8_t val, void *priv)
{
ali1409_t *dev = (ali1409_t *) priv;
ali1409_log ("INPUT:addr %02x ,Value %02x \n" , addr , val);
ali1409_log("[%04X:%08X] [W] %04X = %02X\n", CS, cpu_state.pc, addr, val);
if (addr & 1) {
if (dev->cfg_locked) {
if (dev->last_reg == 0x14 && val == 0x09)
dev->cfg_locked = 0;
if (addr & 0x0001) {
if (dev->cfg_locked) {
if ((dev->last_reg == 0x14) && (val == 0x09))
dev->cfg_locked = 0;
dev->last_reg = val;
return;
}
dev->last_reg = val;
return;
}
if (dev->index == 0xff && val == 0xff)
dev->cfg_locked = 1;
else {
ali1409_log("Write reg %02x %02x %08x\n", dev->index, val, cs);
dev->regs[dev->index] = val;
/* It appears writing anything at all to register 0xFF locks it again. */
if (dev->index == 0xff)
dev->cfg_locked = 1;
else if (dev->index < 0x44) {
ali1409_log("[%04X:%08X] [W] Register %02X = %02X\n", CS, cpu_state.pc, dev->index, val);
switch (dev->index) {
case 0xa:
switch ((val >> 4) & 3) {
case 0:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL);
break;
case 1:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL);
break;
case 2:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL);
break;
case 3:
mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
if (dev->index < 0x10) {
dev->regs[dev->index] = val;
/*
There are still a lot of unknown here, but unfortunately, this is
as far as I have been able to come with two BIOS'es that are
available (the Acer 100T and an AMI Color dated 07/07/91).
*/
switch (dev->index) {
case 0x02:
/*
- Bit 7: The RAS address hold time:
- 0: 1/2 T;
- 1: 1 T.
- Bits 6-4: The RAS precharge time:
- 0, 0, 0: 1.5 T;
- 0, 0, 1: 2 T;
- 0, 1, 0: 2.5 T;
- 0, 1, 1: 3 T;
- 1, 0, 0: 3.5 T;
- 1, 0, 1: 4 T;
- 1, 1, 0: Reserved;
- 1, 1, 1: Reserved.
- Bit 3: Early miss cycle:
- 0: Disabled;
- 1: Enabled.
*/
break;
case 0x03:
/*
- Bit 6: CAS pulse for read cycle:
- 0: 1 T;
- 1: 1.5 T or 2 T.
I can not get the 2.5 T or 3 T setting to apply so
I have no idea what bit governs that.
- Bits 5, 4: CAS pulse for write cycle:
- 0, 0: 0.5 T or 1 T;
- 0, 1: 1.5 T or 2 T;
- 1, 0: 2.5 T or 3 T;
- 1, 1: Reserved.
- Bit 3: CAS active for read cycle:
- 0: Disabled;
- 1: Enabled.
- Bit 2: CAS active for write cycle:
- 0: Disabled;
- 1: Enabled.
*/
break;
case 0x06:
/*
- Bits 6-4: Clock divider:
- 0, 0, 0: / 2;
- 0, 0, 1: / 4;
- 0, 1, 0: / 8;
- 0, 1, 1: Reserved;
- 1, 0, 0: / 3;
- 1, 0, 1: / 6;
- 1, 1, 0: / 5;
- 1, 1, 1: / 10.
*/
switch ((val >> 4) & 7) {
default:
case 3: /* Reserved */
cpu_set_isa_speed(7159091);
break;
case 0xb:
switch ((val >> 4) & 3) {
case 0:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY | MEM_WRITE_EXTANY);
break;
case 1:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTANY);
break;
case 2:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTANY| MEM_WRITE_INTERNAL);
break;
case 3:
mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
break;
}
case 0:
cpu_set_isa_speed(cpu_busspeed / 2);
break;
case 1:
cpu_set_isa_speed(cpu_busspeed / 4);
break;
case 2:
cpu_set_isa_speed(cpu_busspeed / 8);
break;
case 4:
cpu_set_isa_speed(cpu_busspeed / 3);
break;
case 5:
cpu_set_isa_speed(cpu_busspeed / 6);
break;
case 6:
cpu_set_isa_speed(cpu_busspeed / 5);
break;
case 7:
cpu_set_isa_speed(cpu_busspeed / 10);
break;
}
break;
case 0x08 ... 0x0b:
ali1409_shadow_recalc(dev);
break;
case 0x0c:
/*
This appears to be turbo in bit 4 (1 = on, 0 = off),
and bus speed in the rest of the bits.
*/
break;
case 0x0d:
cpu_cache_ext_enabled = !!(val & 0x08);
cpu_update_waitstates();
break;
}
} else
dev->index = val;
}
}
} else
dev->index = val;
}
static uint8_t
ali1409_read(uint16_t addr, void *priv)
{
ali1409_log ("reading at %02X\n",addr);
const ali1409_t *dev = (ali1409_t *) priv;
uint8_t ret = 0xff;
if (dev->cfg_locked)
ret = 0xff;
if (addr & 1) {
if ((dev->index >= 0xc0 || dev->index == 0x20) && cpu_iscyrix)
ret = 0xff;
else if (addr & 0x0001) {
if (dev->index < 0x44)
ret = dev->regs[dev->index];
} else
ret = dev->index;
} else
ret = dev->index;
ali1409_log("[%04X:%08X] [R] %04X = %02X\n", CS, cpu_state.pc, addr, ret);
return ret;
}
@@ -166,17 +313,16 @@ ali1409_init(UNUSED(const device_t *info))
dev->cfg_locked = 1;
/* M1409 Ports:
22h Index Port
23h Data Port
*/
ali1409_log ("Bus speed: %i", cpu_busspeed);
ali1409_log("Bus speed: %i\n", cpu_busspeed);
io_sethandler(0x0022, 0x0002, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
io_sethandler(0x037f, 0x0001, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
io_sethandler(0x03f3, 0x0001, ali1409_read, NULL, NULL, ali1409_write, NULL, NULL, dev);
dev->regs[0x0f] = 0x08;
cpu_set_isa_speed(7159091);
cpu_cache_ext_enabled = 0;
cpu_update_waitstates();
return dev;
}

View File

@@ -4264,7 +4264,7 @@ cpu_write(uint16_t addr, uint8_t val, UNUSED(void *priv))
cyrix_addr = val;
else if (addr < 0xf1) switch (cyrix_addr) {
default:
if (cyrix_addr >= 0xc0)
if ((cyrix_addr >= 0xc0) && (cyrix_addr != 0xff))
fatal("Writing unimplemented Cyrix register %02X\n", cyrix_addr);
break;