Ported the most relevant PCem commits to 86Box.
This commit is contained in:
@@ -41,6 +41,7 @@ static struct
|
||||
|
||||
mem_mapping_t shadow_mapping;
|
||||
mem_mapping_t expansion_mapping;
|
||||
mem_mapping_t cache_mapping;
|
||||
|
||||
uint8_t (*planar_read)(uint16_t port);
|
||||
void (*planar_write)(uint16_t port, uint8_t val);
|
||||
@@ -51,8 +52,95 @@ static struct
|
||||
|
||||
uint8_t mem_pos_regs[8];
|
||||
uint8_t mem_2mb_pos_regs[8];
|
||||
|
||||
int pending_cache_miss;
|
||||
} ps2;
|
||||
|
||||
/*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any
|
||||
proper cache emulation, it's faked a bit here.
|
||||
|
||||
Port E2 is used for cache diagnostics. Bit 7 seems to be set on a cache miss,
|
||||
toggling bit 2 seems to clear this. The BIOS performs at least the following
|
||||
tests :
|
||||
|
||||
- Disable RAM, access low 64kb (386) / 8kb (486), execute code from cache to
|
||||
access low memory and verify that there are no cache misses.
|
||||
- Write to low memory using DMA, read low memory and verify that all accesses
|
||||
cause cache misses.
|
||||
- Read low memory, verify that first access is cache miss. Read again and
|
||||
verify that second access is cache hit.
|
||||
|
||||
These tests are also performed on the 486 model 70, despite there being no
|
||||
external cache on this system. Port E2 seems to control the internal cache on
|
||||
these systems. Presumably this port is connected to KEN#/FLUSH# on the 486.
|
||||
This behaviour is required to pass the timer interrupt test on the 486 version
|
||||
- the BIOS uses a fixed length loop that will terminate too early on a 486/25
|
||||
if it executes from internal cache.
|
||||
|
||||
To handle this, 86Box uses some basic heuristics :
|
||||
- If cache is enabled but RAM is disabled, accesses to low memory go directly
|
||||
to cache memory.
|
||||
- Reads to cache addresses not 'valid' will set the cache miss flag, and mark
|
||||
that line as valid.
|
||||
- Cache flushes will clear the valid array.
|
||||
- DMA via the undocumented PS/2 command 0xb will clear the valid array.
|
||||
- Disabling the cache will clear the valid array.
|
||||
- Disabling the cache will also mark shadowed ROM areas as using ROM timings.
|
||||
This works around the timing loop mentioned above.
|
||||
*/
|
||||
|
||||
static uint8_t ps2_cache[65536];
|
||||
static int ps2_cache_valid[65536/8];
|
||||
|
||||
static uint8_t ps2_read_cache_ram(uint32_t addr, void *priv)
|
||||
{
|
||||
// pclog("ps2_read_cache_ram: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc);
|
||||
if (!ps2_cache_valid[addr >> 3])
|
||||
{
|
||||
ps2_cache_valid[addr >> 3] = 1;
|
||||
ps2.mem_regs[2] |= 0x80;
|
||||
}
|
||||
else
|
||||
ps2.pending_cache_miss = 0;
|
||||
|
||||
return ps2_cache[addr];
|
||||
}
|
||||
static uint16_t ps2_read_cache_ramw(uint32_t addr, void *priv)
|
||||
{
|
||||
// pclog("ps2_read_cache_ramw: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc);
|
||||
if (!ps2_cache_valid[addr >> 3])
|
||||
{
|
||||
ps2_cache_valid[addr >> 3] = 1;
|
||||
ps2.mem_regs[2] |= 0x80;
|
||||
}
|
||||
else
|
||||
ps2.pending_cache_miss = 0;
|
||||
|
||||
return *(uint16_t *)&ps2_cache[addr];
|
||||
}
|
||||
static uint32_t ps2_read_cache_raml(uint32_t addr, void *priv)
|
||||
{
|
||||
// pclog("ps2_read_cache_raml: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc);
|
||||
if (!ps2_cache_valid[addr >> 3])
|
||||
{
|
||||
ps2_cache_valid[addr >> 3] = 1;
|
||||
ps2.mem_regs[2] |= 0x80;
|
||||
}
|
||||
else
|
||||
ps2.pending_cache_miss = 0;
|
||||
|
||||
return *(uint32_t *)&ps2_cache[addr];
|
||||
}
|
||||
static void ps2_write_cache_ram(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
// pclog("ps2_write_cache_ram: addr=%08x val=%02x %04x:%04x %i\n", addr, val, CS,cpu_state.pc, ins);
|
||||
ps2_cache[addr] = val;
|
||||
}
|
||||
|
||||
void ps2_cache_clean(void)
|
||||
{
|
||||
memset(ps2_cache_valid, 0, sizeof(ps2_cache_valid));
|
||||
}
|
||||
|
||||
static uint8_t ps2_read_shadow_ram(uint32_t addr, void *priv)
|
||||
{
|
||||
@@ -139,6 +227,30 @@ static uint8_t model_55sx_read(uint16_t port)
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static uint8_t model_70_type3_read(uint16_t port)
|
||||
{
|
||||
switch (port)
|
||||
{
|
||||
case 0x100:
|
||||
return 0xff;
|
||||
case 0x101:
|
||||
return 0xf9;
|
||||
case 0x102:
|
||||
return ps2.option[0];
|
||||
case 0x103:
|
||||
return ps2.option[1];
|
||||
case 0x104:
|
||||
return ps2.option[2];
|
||||
case 0x105:
|
||||
return ps2.option[3];
|
||||
case 0x106:
|
||||
return ps2.subaddr_lo;
|
||||
case 0x107:
|
||||
return ps2.subaddr_hi;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static uint8_t model_80_read(uint16_t port)
|
||||
{
|
||||
switch (port)
|
||||
@@ -296,6 +408,56 @@ static void model_55sx_write(uint16_t port, uint8_t val)
|
||||
}
|
||||
}
|
||||
|
||||
static void model_70_type3_write(uint16_t port, uint8_t val)
|
||||
{
|
||||
switch (port)
|
||||
{
|
||||
case 0x100:
|
||||
break;
|
||||
case 0x101:
|
||||
break;
|
||||
case 0x102:
|
||||
lpt1_remove();
|
||||
serial_remove(1);
|
||||
if (val & 0x04)
|
||||
{
|
||||
if (val & 0x08)
|
||||
serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ);
|
||||
else
|
||||
serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ);
|
||||
}
|
||||
else
|
||||
serial_remove(1);
|
||||
if (val & 0x10)
|
||||
{
|
||||
switch ((val >> 5) & 3)
|
||||
{
|
||||
case 0:
|
||||
lpt1_init(0x3bc);
|
||||
break;
|
||||
case 1:
|
||||
lpt1_init(0x378);
|
||||
break;
|
||||
case 2:
|
||||
lpt1_init(0x278);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ps2.option[0] = val;
|
||||
break;
|
||||
case 0x105:
|
||||
ps2.option[3] = val;
|
||||
break;
|
||||
case 0x106:
|
||||
ps2.subaddr_lo = val;
|
||||
break;
|
||||
case 0x107:
|
||||
ps2.subaddr_hi = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void model_80_write(uint16_t port, uint8_t val)
|
||||
{
|
||||
switch (port)
|
||||
@@ -737,6 +899,169 @@ static void mem_encoding_write(uint16_t addr, uint8_t val, void *p)
|
||||
mem_encoding_update();
|
||||
}
|
||||
|
||||
static uint8_t mem_encoding_read_cached(uint16_t addr, void *p)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xe0:
|
||||
return ps2.mem_regs[0];
|
||||
case 0xe1:
|
||||
return ps2.mem_regs[1];
|
||||
case 0xe2:
|
||||
return ps2.mem_regs[2];
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void mem_encoding_write_cached(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
uint8_t old;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0xe0:
|
||||
ps2.mem_regs[0] = val;
|
||||
break;
|
||||
case 0xe1:
|
||||
ps2.mem_regs[1] = val;
|
||||
break;
|
||||
case 0xe2:
|
||||
old = ps2.mem_regs[2];
|
||||
ps2.mem_regs[2] = (ps2.mem_regs[2] & 0x80) | (val & ~0x88);
|
||||
if (val & 2)
|
||||
{
|
||||
// pclog("Clear latch - %i\n", ps2.pending_cache_miss);
|
||||
if (ps2.pending_cache_miss)
|
||||
ps2.mem_regs[2] |= 0x80;
|
||||
else
|
||||
ps2.mem_regs[2] &= ~0x80;
|
||||
ps2.pending_cache_miss = 0;
|
||||
}
|
||||
|
||||
if ((val & 0x21) == 0x20 && (old & 0x21) != 0x20)
|
||||
ps2.pending_cache_miss = 1;
|
||||
if ((val & 0x21) == 0x01 && (old & 0x21) != 0x01)
|
||||
ps2_cache_clean();
|
||||
if (val & 0x01)
|
||||
ram_mid_mapping.flags |= MEM_MAPPING_ROM;
|
||||
else
|
||||
ram_mid_mapping.flags &= ~MEM_MAPPING_ROM;
|
||||
break;
|
||||
}
|
||||
// pclog("mem_encoding_write: addr=%02x val=%02x %04x:%04x %02x %02x\n", addr, val, CS,cpu_state.pc, ps2.mem_regs[1],ps2.mem_regs[2]);
|
||||
mem_encoding_update();
|
||||
if ((ps2.mem_regs[1] & 0x10) && (ps2.mem_regs[2] & 0x21) == 0x20)
|
||||
{
|
||||
mem_mapping_disable(&ram_low_mapping);
|
||||
mem_mapping_enable(&ps2.cache_mapping);
|
||||
flushmmucache();
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_mapping_disable(&ps2.cache_mapping);
|
||||
mem_mapping_enable(&ram_low_mapping);
|
||||
flushmmucache();
|
||||
}
|
||||
}
|
||||
|
||||
static void ps2_mca_board_model_70_type34_init(int is_type4)
|
||||
{
|
||||
ps2_mca_board_common_init();
|
||||
|
||||
mem_remap_top_256k();
|
||||
ps2.split_addr = mem_size * 1024;
|
||||
mca_init(4);
|
||||
|
||||
ps2.planar_read = model_70_type3_read;
|
||||
ps2.planar_write = model_70_type3_write;
|
||||
|
||||
device_add(&ps2_nvr_device);
|
||||
|
||||
io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached, NULL, NULL, NULL);
|
||||
|
||||
ps2.mem_regs[1] = 2;
|
||||
|
||||
switch (mem_size/1024)
|
||||
{
|
||||
case 2:
|
||||
ps2.option[1] = 0xa6;
|
||||
ps2.option[2] = 0x01;
|
||||
break;
|
||||
case 4:
|
||||
ps2.option[1] = 0xaa;
|
||||
ps2.option[2] = 0x01;
|
||||
break;
|
||||
case 6:
|
||||
ps2.option[1] = 0xca;
|
||||
ps2.option[2] = 0x01;
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
ps2.option[1] = 0xca;
|
||||
ps2.option[2] = 0x02;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_type4)
|
||||
ps2.option[2] |= 0x04; /*486 CPU*/
|
||||
|
||||
mem_mapping_add(&ps2.cache_mapping,
|
||||
0,
|
||||
is_type4 ? (8 * 1024) : (64 * 1024),
|
||||
ps2_read_cache_ram,
|
||||
ps2_read_cache_ramw,
|
||||
ps2_read_cache_raml,
|
||||
ps2_write_cache_ram,
|
||||
NULL,
|
||||
NULL,
|
||||
ps2_cache,
|
||||
MEM_MAPPING_INTERNAL,
|
||||
NULL);
|
||||
mem_mapping_disable(&ps2.cache_mapping);
|
||||
|
||||
if (mem_size > 8192)
|
||||
{
|
||||
/* Only 8 MB supported on planar, create a memory expansion card for the rest */
|
||||
mem_mapping_set_addr(&ram_high_mapping, 0x100000, 0x700000);
|
||||
|
||||
ps2.mem_pos_regs[0] = 0xff;
|
||||
ps2.mem_pos_regs[1] = 0xfc;
|
||||
|
||||
switch (mem_size/1024)
|
||||
{
|
||||
case 10:
|
||||
ps2.mem_pos_regs[4] = 0xfe;
|
||||
break;
|
||||
case 12:
|
||||
ps2.mem_pos_regs[4] = 0xfa;
|
||||
break;
|
||||
case 14:
|
||||
ps2.mem_pos_regs[4] = 0xea;
|
||||
break;
|
||||
case 16:
|
||||
ps2.mem_pos_regs[4] = 0xaa;
|
||||
break;
|
||||
}
|
||||
|
||||
mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL);
|
||||
mem_mapping_add(&ps2.expansion_mapping,
|
||||
0x800000,
|
||||
(mem_size - 8192)*1024,
|
||||
mem_read_ram,
|
||||
mem_read_ramw,
|
||||
mem_read_raml,
|
||||
mem_write_ram,
|
||||
mem_write_ramw,
|
||||
mem_write_raml,
|
||||
&ram[0x800000],
|
||||
MEM_MAPPING_INTERNAL,
|
||||
NULL);
|
||||
mem_mapping_disable(&ps2.expansion_mapping);
|
||||
}
|
||||
|
||||
device_add(&ps1vga_device);
|
||||
}
|
||||
|
||||
static void ps2_mca_board_model_80_type2_init(int is486)
|
||||
{
|
||||
ps2_mca_board_common_init();
|
||||
@@ -876,6 +1201,21 @@ machine_ps2_model_55sx_init(machine_t *model)
|
||||
ps2_mca_board_model_55sx_init();
|
||||
}
|
||||
|
||||
void
|
||||
machine_ps2_model_70_type3_init(machine_t *model)
|
||||
{
|
||||
machine_ps2_common_init(model);
|
||||
|
||||
ps2_mca_board_model_70_type34_init(0);
|
||||
}
|
||||
|
||||
void
|
||||
machine_ps2_model_70_type4_init(machine_t *model)
|
||||
{
|
||||
machine_ps2_common_init(model);
|
||||
|
||||
ps2_mca_board_model_70_type34_init(1);
|
||||
}
|
||||
|
||||
void
|
||||
machine_ps2_model_80_init(machine_t *model)
|
||||
|
||||
Reference in New Issue
Block a user