i386: Improve splitting of unaligned accesses (excluding program fetches)

(nw) This entails a major code reorganization just to keep the scale of it all halfway sane.
This commit is contained in:
AJR 2019-05-19 17:41:44 -04:00
parent e4f9fc8d82
commit 6fff18773b
11 changed files with 4864 additions and 4272 deletions

View File

@ -1087,6 +1087,8 @@ if (CPUS["I386"]~=null) then
files {
MAME_DIR .. "src/devices/cpu/i386/i386.cpp",
MAME_DIR .. "src/devices/cpu/i386/i386.h",
MAME_DIR .. "src/devices/cpu/i386/athlon.cpp",
MAME_DIR .. "src/devices/cpu/i386/athlon.h",
MAME_DIR .. "src/devices/cpu/i386/cache.h",
MAME_DIR .. "src/devices/cpu/i386/cycles.h",
MAME_DIR .. "src/devices/cpu/i386/i386op16.hxx",
@ -1094,6 +1096,7 @@ if (CPUS["I386"]~=null) then
MAME_DIR .. "src/devices/cpu/i386/i386ops.h",
MAME_DIR .. "src/devices/cpu/i386/i386ops.hxx",
MAME_DIR .. "src/devices/cpu/i386/i386priv.h",
MAME_DIR .. "src/devices/cpu/i386/i386segs.hxx",
MAME_DIR .. "src/devices/cpu/i386/i486ops.hxx",
MAME_DIR .. "src/devices/cpu/i386/pentops.hxx",
MAME_DIR .. "src/devices/cpu/i386/x87ops.hxx",

View File

@ -0,0 +1,954 @@
// license:BSD-3-Clause
// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett
#include "emu.h"
#include "athlon.h"
#include "i386priv.h"
DEFINE_DEVICE_TYPE(ATHLONXP, athlonxp_device, "athlonxp", "Amd Athlon XP")
athlonxp_device::athlonxp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: pentium_device(mconfig, ATHLONXP, tag, owner, clock)
, m_data_config("mmio", ENDIANNESS_LITTLE, 32, 32, 0, 32, 12)
, m_opcodes_config("debugger", ENDIANNESS_LITTLE, 32, 32, 0, 32, 12)
{
// TODO: put correct value
set_vtlb_dynamic_entries(256);
}
/*****************************************************************************/
/* AMD Athlon XP
Model: Athlon XP 2400+
Part number: AXDA2400DKV3C
Stepping code: AIUCP
Date code: 0240MPMW
*/
void athlonxp_device::device_start()
{
i386_common_init();
register_state_i386_x87_xmm();
m_data = &space(AS_DATA);
m_opcodes = &space(AS_OPCODES);
mmacache32 = m_data->cache<2, 0, ENDIANNESS_LITTLE>();
m_opcodes->install_read_handler(0, 0xffffffff, read32_delegate(FUNC(athlonxp_device::debug_read_memory), this));
build_x87_opcode_table();
build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_PPRO | OP_MMX | OP_SSE);
m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM].get(); // TODO: generate own cycle tables
m_cycle_table_pm = cycle_table_pm[CPU_CYCLES_PENTIUM].get(); // TODO: generate own cycle tables
// put savestate calls here
save_item(NAME(m_processor_name_string));
save_item(NAME(m_msr_top_mem));
save_item(NAME(m_msr_sys_cfg));
save_item(NAME(m_msr_smm_base));
save_item(NAME(m_msr_smm_mask));
save_item(NAME(m_msr_mtrrfix));
save_item(NAME(m_memory_ranges_1m));
}
void athlonxp_device::device_reset()
{
zero_state();
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
m_sreg[CS].limit = 0xffff;
m_sreg[CS].flags = 0x0093;
m_sreg[DS].base = m_sreg[ES].base = m_sreg[FS].base = m_sreg[GS].base = m_sreg[SS].base = 0x00000000;
m_sreg[DS].limit = m_sreg[ES].limit = m_sreg[FS].limit = m_sreg[GS].limit = m_sreg[SS].limit = 0xffff;
m_sreg[DS].flags = m_sreg[ES].flags = m_sreg[FS].flags = m_sreg[GS].flags = m_sreg[SS].flags = 0x0093;
m_idtr.base = 0;
m_idtr.limit = 0x3ff;
m_a20_mask = ~0;
m_cr[0] = 0x60000010;
m_eflags = 0x00200000;
m_eflags_mask = 0x00277fd7; /* TODO: is this correct? */
m_eip = 0xfff0;
m_mxcsr = 0x1f80;
m_smm = false;
m_smi_latched = false;
m_smbase = 0x30000;
m_nmi_masked = false;
m_nmi_latched = false;
x87_reset();
// [11:8] Family
// [ 7:4] Model
// [ 3:0] Stepping ID
// Family 6, Model 8, Stepping 1
REG32(EAX) = 0;
REG32(EDX) = (6 << 8) | (8 << 4) | (1);
m_cpuid_id0 = ('h' << 24) | ('t' << 16) | ('u' << 8) | 'A'; // Auth
m_cpuid_id1 = ('i' << 24) | ('t' << 16) | ('n' << 8) | 'e'; // enti
m_cpuid_id2 = ('D' << 24) | ('M' << 16) | ('A' << 8) | 'c'; // cAMD
memset(m_processor_name_string, 0, 48);
strcpy((char *)m_processor_name_string, "AMD Athlon(tm) Processor");
for (int n = 0; n < 11; n++)
m_msr_mtrrfix[n] = 0;
for (int n = 0; n < (1024 / 4); n++)
m_memory_ranges_1m[n] = 0;
m_msr_top_mem = 1024 * 1024;
m_msr_sys_cfg = 0;
m_msr_smm_base = m_smbase;
m_msr_smm_mask = 0;
m_cpuid_max_input_value_eax = 0x01;
m_cpu_version = REG32(EDX);
// see FEATURE_FLAGS enum for bit names
m_feature_flags = 0x0383fbff;
CHANGE_PC(m_eip);
}
device_memory_interface::space_config_vector athlonxp_device::memory_space_config() const
{
return space_config_vector{
std::make_pair(AS_PROGRAM, &m_program_config),
std::make_pair(AS_IO, &m_io_config),
std::make_pair(AS_DATA, &m_data_config),
std::make_pair(AS_OPCODES, &m_opcodes_config)
};
}
void athlonxp_device::enter_smm()
{
u64 data;
if (m_msr_smm_mask & 1)
data = 0x1818181818181818; // when smm is active
else
data = m_msr_mtrrfix[2];
parse_mtrrfix(data, 0xa0000, 16);
i386_device::enter_smm();
}
void athlonxp_device::leave_smm()
{
u64 data;
i386_device::leave_smm();
if (m_msr_smm_mask & 1)
data = 0; // when smm is not active
else
data = m_msr_mtrrfix[2];
parse_mtrrfix(data, 0xa0000, 16);
}
void athlonxp_device::parse_mtrrfix(u64 mtrr, offs_t base, int kblock)
{
int nb = kblock / 4;
int range = (int)(base >> 12); // base must never be higher than 1 megabyte
for (int n = 0; n < 8; n++)
{
uint8_t type = mtrr & 0xff;
for (int b = 0; b < nb; b++)
{
m_memory_ranges_1m[range] = type;
range++;
}
mtrr = mtrr >> 8;
}
}
int athlonxp_device::check_cacheable(offs_t address)
{
offs_t block;
int disabled;
disabled = 0;
if (m_cr[0] & (1 << 30))
disabled = 128;
if (address >= 0x100000)
return disabled;
block = address >> 12;
return m_memory_ranges_1m[block] | disabled;
}
template <int wr>
int athlonxp_device::address_mode(offs_t address)
{
if (address >= m_msr_top_mem)
return 1;
if (address >= 1 * 1024 * 1024)
return 0;
if ((m_memory_ranges_1m[address >> 12] & (1 << (3 + wr))) != 0)
return 0;
return 1;
}
READ32_MEMBER(athlonxp_device::debug_read_memory)
{
offs_t address = offset << 2;
int mode = check_cacheable(address);
bool nocache = false;
address_space *m = m_program;
u8 *data;
if ((mode & 7) == 0)
nocache = true;
if (mode & 1)
nocache = true;
if (nocache == false)
{
int offset = (address & 63);
data = cache.search<CacheRead>(address);
if (data)
return *(u32 *)(data + offset);
}
if (address_mode<1>(address))
m = m_data;
return m->read_dword(address);
}
template <class dt, offs_t xorle>
dt athlonxp_device::opcode_read_cache(offs_t address)
{
int mode = check_cacheable(address);
bool nocache = false;
memory_access_cache<2, 0, ENDIANNESS_LITTLE> *m = macache32;
u8 *data;
if ((mode & 7) == 0)
nocache = true;
if (mode & 1)
nocache = true;
if (nocache == false)
{
int offset = (address & 63) ^ xorle;
data = cache.search<CacheRead>(address);
if (data)
return *(dt *)(data + offset);
if (!(mode & 128))
{
bool dirty = cache.allocate<CacheRead>(address, &data);
address = cache.base(address);
if (dirty)
{
offs_t old_address = cache.old();
for (int w = 0; w < 64; w += 4)
m->write_dword(old_address + w, *(u32 *)(data + w));
}
for (int r = 0; r < 64; r += 4)
*(u32 *)(data + r) = m->read_dword(address + r);
return *(dt *)(data + offset);
}
}
if (address_mode<1>(address))
m = mmacache32;
if (sizeof(dt) == 1)
return m->read_byte(address);
else if (sizeof(dt) == 2)
return m->read_word(address);
else
return m->read_dword(address);
}
uint32_t athlonxp_device::program_read_cache(offs_t address, uint32_t mask)
{
int mode = check_cacheable(address);
bool nocache = false;
address_space *m = m_program;
u8 *data;
if ((mode & 7) == 0)
nocache = true;
if (mode & 1)
nocache = true;
if (nocache == false)
{
int offset = address & 63;
data = cache.search<CacheRead>(address);
if (data)
return *(u32 *)(data + offset) & mask;
if (!(mode & 128))
{
bool dirty = cache.allocate<CacheRead>(address, &data);
address = cache.base(address);
if (dirty)
{
offs_t old_address = cache.old();
for (int w = 0; w < 64; w += 4)
m->write_dword(old_address + w, *(u32 *)(data + w));
}
for (int r = 0; r < 64; r += 4)
*(u32 *)(data + r) = m->read_dword(address + r);
return *(u32 *)(data + offset) & mask;
}
}
if (address_mode<1>(address))
m = m_data;
return m->read_dword(address, mask) & mask;
}
void athlonxp_device::program_write_cache(offs_t address, uint32_t data, uint32_t mask)
{
int mode = check_cacheable(address);
bool nocache = false;
address_space *m = m_program;
u8 *dataw;
if ((mode & 7) == 0)
nocache = true;
if (mode & 1)
nocache = true;
if (nocache == false)
{
int offset = address & 63;
dataw = cache.search<CacheWrite>(address);
if (dataw)
{
*(u32 *)(dataw + offset) = (*(u32 *)(dataw + offset) & ~mask) | (data & mask);
return;
}
if (!(mode & 128))
{
bool dirty = cache.allocate<CacheWrite>(address, &dataw);
address = cache.base(address);
if (dirty)
{
offs_t old_address = cache.old();
for (int w = 0; w < 64; w += 4)
m->write_dword(old_address + w, *(u32 *)(dataw + w));
}
for (int r = 0; r < 64; r += 4)
*(u32 *)(dataw + r) = m->read_dword(address + r);
*(u32 *)(dataw + offset) = (*(u32 *)(dataw + offset) & ~mask) | (data & mask);
return;
}
}
if (address_mode<0>(address))
m = m_data;
m->write_dword(address, data, mask);
}
void athlonxp_device::cache_writeback()
{
// dirty cachelines are written back to memory
address_space *m = m_program;
u32 base;
u8 *data;
data = cache.first_dirty(base, false);
while (data != nullptr)
{
for (int w = 0; w < 64; w += 4)
m->write_dword(base + w, *(u32 *)(data + w));
data = cache.next_dirty(base, false);
}
}
void athlonxp_device::cache_invalidate()
{
// dirty cachelines are not written back to memory
cache.reset();
}
void athlonxp_device::cache_clean()
{
// dirty cachelines are marked as clean but not written back to memory
u32 base;
u8 *data;
data = cache.first_dirty(base, true);
while (data != nullptr)
data = cache.next_dirty(base, true);
}
uint8_t athlonxp_device::READ8PL(uint32_t ea, uint8_t privilege)
{
uint32_t address = ea, error;
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
uint8_t shift = 8 * (ea & 3);
return program_read_cache(address - (ea & 3), uint32_t(0xff) << shift) >> shift;
}
uint16_t athlonxp_device::READ16PL(uint32_t ea, uint8_t privilege)
{
uint16_t value;
uint32_t address = ea, error;
switch (ea & 3)
{
case 0:
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
value = program_read_cache(address, 0x0000ffff) & 0xffff;
break;
case 1:
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
value = (program_read_cache(address - 1, 0x00ffff00) >> 8) & 0xffff;
break;
case 2:
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
value = (program_read_cache(address - 2, 0xffff0000) >> 16) & 0xffff;
break;
case 3:
value = READ8PL(ea, privilege);
value |= READ8PL(ea + 1, privilege) << 8;
break;
}
return value;
}
uint32_t athlonxp_device::READ32PL(uint32_t ea, uint8_t privilege)
{
uint32_t value;
uint32_t address = ea, error;
switch (ea & 3)
{
case 0:
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
value = program_read_cache(address, 0xffffffff);
break;
case 1:
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
value = program_read_cache(address - 1, 0xffffff00) >> 8;
value |= READ8PL(ea + 3, privilege) << 24;
break;
case 2:
value = READ16PL(ea, privilege);
value |= READ16PL(ea + 2, privilege) << 16;
break;
case 3:
value = READ8PL(ea, privilege);
address = ea + 1;
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
value |= program_read_cache(address, 0x00ffffff) << 8;
break;
}
return value;
}
uint64_t athlonxp_device::READ64PL(uint32_t ea, uint8_t privilege)
{
uint64_t value;
uint32_t address = ea, error;
switch (ea & 3)
{
case 0:
value = READ32PL(ea, privilege);
value |= uint64_t(READ32PL(ea + 2, privilege)) << 32;
break;
case 1:
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
value = program_read_cache(address - 1, 0xffffff00) >> 8;
value |= uint64_t(READ32PL(ea + 3, privilege)) << 24;
value |= uint64_t(READ8PL(ea + 7, privilege)) << 56;
break;
case 2:
value = READ16PL(ea, privilege);
value |= uint64_t(READ32PL(ea + 2, privilege)) << 16;
value |= uint64_t(READ16PL(ea + 6, privilege)) << 48;
break;
case 3:
value = READ8PL(ea, privilege);
value |= uint64_t(READ32PL(ea + 1, privilege)) << 8;
address = ea + 5;
if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
value |= uint64_t(program_read_cache(address, 0x00ffffff)) << 40;
break;
}
return value;
}
void athlonxp_device::WRITE8PL(uint32_t ea, uint8_t privilege, uint8_t value)
{
uint32_t address = ea, error;
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
uint8_t shift = 8 * (ea & 3);
program_write_cache(address - (ea & 3), value << shift, uint32_t(0xff) << shift);
}
void athlonxp_device::WRITE16PL(uint32_t ea, uint8_t privilege, uint16_t value)
{
uint32_t address = ea, error;
switch(ea & 3)
{
case 0:
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
program_write_cache(address, value, 0x0000ffff);
break;
case 1:
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
program_write_cache(address - 1, value << 8, 0x00ffff00);
break;
case 2:
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
program_write_cache(address - 2, value << 16, 0xffff0000);
break;
case 3:
WRITE8PL(ea, privilege, value & 0xff);
WRITE8PL(ea + 1, privilege, (value >> 8) & 0xff);
break;
}
}
void athlonxp_device::WRITE32PL(uint32_t ea, uint8_t privilege, uint32_t value)
{
uint32_t address = ea, error;
switch(ea & 3)
{
case 0:
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
program_write_cache(address, value, 0xffffffff);
break;
case 1:
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
program_write_cache(address - 1, (value << 8) & 0xffffff00, 0xffffff00);
WRITE8PL(ea + 3, privilege, (value >> 24) & 0xff);
break;
case 2:
WRITE16PL(ea, privilege, value & 0xffff);
WRITE16PL(ea + 2, privilege, (value >> 16) & 0xffff);
break;
case 3:
WRITE8PL(ea, privilege, value & 0xff);
address = ea + 1;
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
program_write_cache(address, value >> 8, 0x00ffffff);
break;
}
}
void athlonxp_device::WRITE64PL(uint32_t ea, uint8_t privilege, uint64_t value)
{
uint32_t address = ea, error;
switch(ea & 3)
{
case 0:
WRITE32PL(ea, privilege, value & 0xffffffff);
WRITE32PL(ea + 2, privilege, (value >> 32) & 0xffffffff);
break;
case 1:
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
program_write_cache(address - 1, value << 8, 0xffffff00);
WRITE32PL(ea + 3, privilege, (value >> 24) & 0xffffffff);
WRITE8PL(ea + 7, privilege, (value >> 56) & 0xff );
break;
case 2:
WRITE16PL(ea, privilege, value & 0xffff);
WRITE32PL(ea + 2, privilege, (value >> 16) & 0xffffffff);
WRITE16PL(ea + 6, privilege, (value >> 48) & 0xffff);
break;
case 3:
WRITE8PL(ea, privilege, value & 0xff);
WRITE32PL(ea + 1, privilege, (value >> 8) & 0xffffffff);
address = ea + 5;
if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
PF_THROW(error);
address &= m_a20_mask;
program_write_cache(address, (value >> 40) & 0x00ffffff, 0x00ffffff);
break;
}
}
/**********************************************************************************/
void athlonxp_device::opcode_cpuid()
{
switch (REG32(EAX))
{
case 0x80000000:
{
REG32(EAX) = 0x80000008;
REG32(EBX) = m_cpuid_id0;
REG32(ECX) = m_cpuid_id2;
REG32(EDX) = m_cpuid_id1;
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000001:
{
REG32(EAX) = m_cpu_version + 0x100; // family+1 as specified in AMD documentation
REG32(EDX) = m_feature_flags;
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000002:
case 0x80000003:
case 0x80000004:
{
int offset = (REG32(EAX) - 0x80000002) << 4;
uint8_t *b = m_processor_name_string + offset;
REG32(EAX) = b[ 0] + (b[ 1] << 8) + (b[ 2] << 16) + (b[ 3] << 24);
REG32(EBX) = b[ 4] + (b[ 5] << 8) + (b[ 6] << 16) + (b[ 7] << 24);
REG32(ECX) = b[ 8] + (b[ 9] << 8) + (b[10] << 16) + (b[11] << 24);
REG32(EDX) = b[12] + (b[13] << 8) + (b[14] << 16) + (b[15] << 24);
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000005:
{
REG32(EAX) = 0x0408FF08; // 2M/4M data tlb associativity 04 data tlb number of entries 08 instruction tlb associativity FF instruction tlb number of entries 08
REG32(EBX) = 0xFF20FF10; // 4K data tlb associativity FF data tlb number of entries 20 instruction tlb associativity FF instruction tlb number of entries 10
REG32(ECX) = 0x40020140; // L1 data cache size in K 40 associativity 02 lines per tag 01 line size in bytes 40
REG32(EDX) = 0x40020140; // L1 instruction cache size in K 40 associativity 02 lines per tag 01 line size in bytes 40
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000006:
{
REG32(EAX) = 0;
REG32(EBX) = 0x41004100; // 4 100 4 100
REG32(ECX) = 0x01008140; // L2 cache size in K 0100 associativity 8=16-way lines per tag 1 line size in bytes 40
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000007:
{
REG32(EDX) = 1; // Advanced power management information, temperature sensor present
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000008:
{
REG32(EAX) = 0x00002022;
CYCLES(CYCLES_CPUID);
break;
}
default:
i386_device::opcode_cpuid();
}
}
uint64_t athlonxp_device::opcode_rdmsr(bool &valid_msr)
{
uint64_t ret;
uint32_t offset = REG32(ECX);
ret = 0;
switch (offset)
{
case 0x10: // TSC
break;
case 0x1b: // APIC_BASE
break;
case 0xfe: // MTRRcap
// 7-0 MTRRCapVCnt - Number of variable range MTRRs (8)
// 8 MtrrCapFix - Fixed range MTRRs available (1)
// 10 MtrrCapWc - Write combining memory type available (1)
ret = 0x508;
break;
case 0x17b: // MCG_CTL
break;
case 0x200: // MTRRphysBase0-7
case 0x202:
case 0x204:
case 0x206:
case 0x208:
case 0x20a:
case 0x20c:
case 0x20e:
// 7-0 Type - Memory type for this memory range
// 39-12 PhyBase27-0 - Base address for this memory range
/* Format of type field:
Bits 2-0 specify the memory type with the following encoding
0 UC Uncacheable
1 WC Write Combining
4 WT Write Through
5 WP Write Protect
6 WB Write Back
7 UC Uncacheable used only in PAT register
Bit 3 WrMem 1 write to memory 0 write to mmio, present only in fixed range MTRRs
Bit 4 RdMem 1 read from memory 0 read from mmio, present only in fixed range MTRRs
Other bits are unused
*/
break;
case 0x201: // MTRRphysMask0-7
case 0x203:
case 0x205:
case 0x207:
case 0x209:
case 0x20b:
case 0x20d:
case 0x20f:
// 11 Valid - Memory range active
// 39-12 PhyMask27-0 - Address mask
break;
case 0x2ff: // MTRRdefType
// 7-0 MtrrDefMemType - Default memory type
// 10 MtrrDefTypeFixEn - Enable fixed range MTRRs
// 11 MtrrDefTypeEn - Enable MTRRs
break;
case 0x250: // MTRRfix64K_00000
// 8 bits for each 64k block starting at address 0
ret = m_msr_mtrrfix[0];
break;
case 0x258: // MTRRfix16K_80000
// 8 bits for each 16k block starting at address 0x80000
ret = m_msr_mtrrfix[1];
break;
case 0x259: // MTRRfix16K_A0000
// 8 bits for each 16k block starting at address 0xa0000
ret = m_msr_mtrrfix[2];
break;
case 0x268: // MTRRfix4K_C0000
case 0x269: // MTRRfix4K_C8000
case 0x26a: // MTRRfix4K_D0000
case 0x26b: // MTRRfix4K_D8000
case 0x26c: // MTRRfix4K_E0000
case 0x26d: // MTRRfix4K_E8000
case 0x26e: // MTRRfix4K_F0000
case 0x26f: // MTRRfix4K_F8000
// 8 bits for each 4k block
ret = m_msr_mtrrfix[3 + offset - 0x268];
break;
case 0x400: // MC0_CTL
break;
case 0x404: // MC1_CTL
break;
case 0x408: // MC2_CTL
break;
case 0x40c: // MC3_CTL
break;
case 0xC0010010: // SYS_CFG
// 20 MtrrVarDramEn - Enable top of memory address and I/O range registers
// 19 MtrrFixDramModEn - Enable modification of RdDram and WrDram bits in fixed MTRRs
// 18 MtrrFixDramEn - Enable RdDram and WrDram attributes in fixed MTRRs
ret = m_msr_sys_cfg;
break;
case 0xC0010015: // HWCR
break;
case 0xC0010016: // IORRBase0-1
case 0xC0010018:
// 39-12 Base27-0 - Base address for this memory range
// 4 RdDram - Read from DRAM
// 3 WrDram - Write to DRAM
break;
case 0xC0010017: // IORRMask0-1
case 0xC0010019:
// 39-12 Mask27-0 - Address mask
// 11 V - Register enabled
break;
case 0xC001001A: // TOP_MEM
// 39-23 TOM16-0 - Top of Memory, accesses from this address onward are directed to mmio
ret = (uint64_t)m_msr_top_mem;
break;
case 0xC001001D: // TOP_MEM2
break;
case 0xC0010111: // SMM_BASE
// address of system management mode area
ret = (uint64_t)m_msr_smm_base;
break;
case 0xC0010113: // SMM_MASK
// 1 TValid - Enable TSeg SMRAM Range
// 0 AValid - Enable ASeg SMRAM Range
/* Access to the ASeg (a0000-bffff) depends on bit 0 of smm_mask
if the bit is 0 use the associated fixed mtrr
if the bit is 1
if smm is active
access goes to dram (wrmem 1 rdmem 1)
if smm not active
access goes to mmio (wrmem 0 rdmem 0) */
ret = m_msr_smm_mask;
break;
}
valid_msr = true;
return ret;
}
void athlonxp_device::opcode_wrmsr(uint64_t data, bool &valid_msr)
{
uint32_t offset = REG32(ECX);
switch (offset)
{
case 0x1b: // APIC_BASE
break;
case 0x17b: // MCG_CTL
break;
case 0x200: // MTRRphysBase0-7
case 0x201: // MTRRphysMask0-7
case 0x202:
case 0x203:
case 0x204:
case 0x205:
case 0x206:
case 0x207:
case 0x208:
case 0x209:
case 0x20a:
case 0x20b:
case 0x20c:
case 0x20d:
case 0x20e:
case 0x20f:
break;
case 0x2ff: // MTRRdefType
break;
case 0x250: // MTRRfix64K_00000
m_msr_mtrrfix[0] = data;
parse_mtrrfix(data, 0, 64);
break;
case 0x258: // MTRRfix16K_80000
m_msr_mtrrfix[1] = data;
parse_mtrrfix(data, 0x80000, 16);
break;
case 0x259: // MTRRfix16K_A0000
m_msr_mtrrfix[2] = data;
if (m_msr_smm_mask & 1)
{
if (m_smm)
data = 0x1818181818181818; // when smm is active
else
data = 0; // when smm is not active
}
parse_mtrrfix(data, 0xa0000, 16);
break;
case 0x268: // MTRRfix4K_C0000-F8000
case 0x269:
case 0x26a:
case 0x26b:
case 0x26c:
case 0x26d:
case 0x26e:
case 0x26f:
m_msr_mtrrfix[3 + offset - 0x268] = data;
parse_mtrrfix(data, 0xc0000 + (offset - 0x268) * 0x8000, 4);
break;
case 0x400: // MC0_CTL
break;
case 0x404: // MC1_CTL
break;
case 0x408: // MC2_CTL
break;
case 0x40c: // MC3_CTL
break;
case 0xC0010010: // SYS_CFG
m_msr_sys_cfg = data;
break;
case 0xC0010015: // HWCR
break;
case 0xC0010016: // IORRBase
case 0xC0010017: // IORRMask
case 0xC0010018:
case 0xC0010019:
break;
case 0xC001001A: // TOP_MEM
m_msr_top_mem = (offs_t)data;
break;
case 0xC0010111: // SMM_BASE
m_msr_smm_base = (offs_t)data;
m_smbase = m_msr_smm_base;
break;
case 0xC0010113: // SMM_MASK
m_msr_smm_mask = data;
if (m_msr_smm_mask & 1)
{
if (m_smm)
data = 0x1818181818181818; // when smm is active
else
data = 0; // when smm is not active
}
else
data = m_msr_mtrrfix[2];
parse_mtrrfix(data, 0xa0000, 16);
break;
}
valid_msr = true;
}

View File

@ -0,0 +1,75 @@
// license:BSD-3-Clause
// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett
#ifndef MAME_CPU_I386_ATHLON_H
#define MAME_CPU_I386_ATHLON_H
#pragma once
#include "i386.h"
#include "cache.h"
class athlonxp_device : public pentium_device
{
public:
// construction/destruction
athlonxp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
virtual void opcode_cpuid() override;
virtual uint64_t opcode_rdmsr(bool &valid_msr) override;
virtual void opcode_wrmsr(uint64_t data, bool &valid_msr) override;
virtual void cache_writeback() override;
virtual void cache_invalidate() override;
virtual void cache_clean() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void enter_smm() override;
virtual void leave_smm() override;
virtual u8 mem_pr8(offs_t address) override { return opcode_read_cache<u8, NATIVE_ENDIAN_VALUE_LE_BE(0, 3)>(address); }
virtual u16 mem_pr16(offs_t address) override { return opcode_read_cache<u16, NATIVE_ENDIAN_VALUE_LE_BE(0, 2)>(address); }
virtual u32 mem_pr32(offs_t address) override { return opcode_read_cache<u32, 0>(address); }
virtual uint8_t READ8PL(uint32_t ea, uint8_t privilege) override;
virtual uint16_t READ16PL(uint32_t ea, uint8_t privilege) override;
virtual uint32_t READ32PL(uint32_t ea, uint8_t privilege) override;
virtual uint64_t READ64PL(uint32_t ea, uint8_t privilege) override;
virtual void WRITE8PL(uint32_t ea, uint8_t privilege, uint8_t value) override;
virtual void WRITE16PL(uint32_t ea, uint8_t privilege, uint16_t value) override;
virtual void WRITE32PL(uint32_t ea, uint8_t privilege, uint32_t value) override;
virtual void WRITE64PL(uint32_t ea, uint8_t privilege, uint64_t value) override;
// device_memory_interface override
virtual space_config_vector memory_space_config() const override;
private:
void parse_mtrrfix(u64 mtrr, offs_t base, int kblock);
inline int check_cacheable(offs_t address);
template <int wr> int address_mode(offs_t address);
template <class dt, offs_t xorle> dt opcode_read_cache(offs_t address);
uint32_t program_read_cache(offs_t address, uint32_t mask);
void program_write_cache(offs_t address, uint32_t data, uint32_t mask);
DECLARE_READ32_MEMBER(debug_read_memory);
address_space_config m_data_config;
address_space *m_data;
address_space_config m_opcodes_config;
address_space *m_opcodes;
memory_access_cache<2, 0, ENDIANNESS_LITTLE> *mmacache32;
uint8_t m_processor_name_string[48];
offs_t m_msr_top_mem;
uint64_t m_msr_sys_cfg;
offs_t m_msr_smm_base;
uint64_t m_msr_smm_mask;
uint64_t m_msr_mtrrfix[11];
uint8_t m_memory_ranges_1m[1024 / 4];
cpucache<17, 9, Cache2Way, CacheLineBytes64> cache; // 512 sets, 2 ways (cachelines per set), 64 bytes per cacheline
};
DECLARE_DEVICE_TYPE(ATHLONXP, athlonxp_device)
#endif // MAME_CPU_I386_ATHLON_H

View File

@ -178,314 +178,3 @@ void pentium4_device::opcode_wrmsr(uint64_t data, bool &valid_msr)
break;
}
}
void athlonxp_device::opcode_cpuid()
{
switch (REG32(EAX))
{
case 0x80000000:
{
REG32(EAX) = 0x80000008;
REG32(EBX) = m_cpuid_id0;
REG32(ECX) = m_cpuid_id2;
REG32(EDX) = m_cpuid_id1;
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000001:
{
REG32(EAX) = m_cpu_version + 0x100; // family+1 as specified in AMD documentation
REG32(EDX) = m_feature_flags;
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000002:
case 0x80000003:
case 0x80000004:
{
int offset = (REG32(EAX) - 0x80000002) << 4;
uint8_t *b = m_processor_name_string + offset;
REG32(EAX) = b[ 0] + (b[ 1] << 8) + (b[ 2] << 16) + (b[ 3] << 24);
REG32(EBX) = b[ 4] + (b[ 5] << 8) + (b[ 6] << 16) + (b[ 7] << 24);
REG32(ECX) = b[ 8] + (b[ 9] << 8) + (b[10] << 16) + (b[11] << 24);
REG32(EDX) = b[12] + (b[13] << 8) + (b[14] << 16) + (b[15] << 24);
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000005:
{
REG32(EAX) = 0x0408FF08; // 2M/4M data tlb associativity 04 data tlb number of entries 08 instruction tlb associativity FF instruction tlb number of entries 08
REG32(EBX) = 0xFF20FF10; // 4K data tlb associativity FF data tlb number of entries 20 instruction tlb associativity FF instruction tlb number of entries 10
REG32(ECX) = 0x40020140; // L1 data cache size in K 40 associativity 02 lines per tag 01 line size in bytes 40
REG32(EDX) = 0x40020140; // L1 instruction cache size in K 40 associativity 02 lines per tag 01 line size in bytes 40
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000006:
{
REG32(EAX) = 0;
REG32(EBX) = 0x41004100; // 4 100 4 100
REG32(ECX) = 0x01008140; // L2 cache size in K 0100 associativity 8=16-way lines per tag 1 line size in bytes 40
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000007:
{
REG32(EDX) = 1; // Advanced power management information, temperature sensor present
CYCLES(CYCLES_CPUID);
break;
}
case 0x80000008:
{
REG32(EAX) = 0x00002022;
CYCLES(CYCLES_CPUID);
break;
}
default:
i386_device::opcode_cpuid();
}
}
uint64_t athlonxp_device::opcode_rdmsr(bool &valid_msr)
{
uint64_t ret;
uint32_t offset = REG32(ECX);
ret = 0;
switch (offset)
{
case 0x10: // TSC
break;
case 0x1b: // APIC_BASE
break;
case 0xfe: // MTRRcap
// 7-0 MTRRCapVCnt - Number of variable range MTRRs (8)
// 8 MtrrCapFix - Fixed range MTRRs available (1)
// 10 MtrrCapWc - Write combining memory type available (1)
ret = 0x508;
break;
case 0x17b: // MCG_CTL
break;
case 0x200: // MTRRphysBase0-7
case 0x202:
case 0x204:
case 0x206:
case 0x208:
case 0x20a:
case 0x20c:
case 0x20e:
// 7-0 Type - Memory type for this memory range
// 39-12 PhyBase27-0 - Base address for this memory range
/* Format of type field:
Bits 2-0 specify the memory type with the following encoding
0 UC Uncacheable
1 WC Write Combining
4 WT Write Through
5 WP Write Protect
6 WB Write Back
7 UC Uncacheable used only in PAT register
Bit 3 WrMem 1 write to memory 0 write to mmio, present only in fixed range MTRRs
Bit 4 RdMem 1 read from memory 0 read from mmio, present only in fixed range MTRRs
Other bits are unused
*/
break;
case 0x201: // MTRRphysMask0-7
case 0x203:
case 0x205:
case 0x207:
case 0x209:
case 0x20b:
case 0x20d:
case 0x20f:
// 11 Valid - Memory range active
// 39-12 PhyMask27-0 - Address mask
break;
case 0x2ff: // MTRRdefType
// 7-0 MtrrDefMemType - Default memory type
// 10 MtrrDefTypeFixEn - Enable fixed range MTRRs
// 11 MtrrDefTypeEn - Enable MTRRs
break;
case 0x250: // MTRRfix64K_00000
// 8 bits for each 64k block starting at address 0
ret = m_msr_mtrrfix[0];
break;
case 0x258: // MTRRfix16K_80000
// 8 bits for each 16k block starting at address 0x80000
ret = m_msr_mtrrfix[1];
break;
case 0x259: // MTRRfix16K_A0000
// 8 bits for each 16k block starting at address 0xa0000
ret = m_msr_mtrrfix[2];
break;
case 0x268: // MTRRfix4K_C0000
case 0x269: // MTRRfix4K_C8000
case 0x26a: // MTRRfix4K_D0000
case 0x26b: // MTRRfix4K_D8000
case 0x26c: // MTRRfix4K_E0000
case 0x26d: // MTRRfix4K_E8000
case 0x26e: // MTRRfix4K_F0000
case 0x26f: // MTRRfix4K_F8000
// 8 bits for each 4k block
ret = m_msr_mtrrfix[3 + offset - 0x268];
break;
case 0x400: // MC0_CTL
break;
case 0x404: // MC1_CTL
break;
case 0x408: // MC2_CTL
break;
case 0x40c: // MC3_CTL
break;
case 0xC0010010: // SYS_CFG
// 20 MtrrVarDramEn - Enable top of memory address and I/O range registers
// 19 MtrrFixDramModEn - Enable modification of RdDram and WrDram bits in fixed MTRRs
// 18 MtrrFixDramEn - Enable RdDram and WrDram attributes in fixed MTRRs
ret = m_msr_sys_cfg;
break;
case 0xC0010015: // HWCR
break;
case 0xC0010016: // IORRBase0-1
case 0xC0010018:
// 39-12 Base27-0 - Base address for this memory range
// 4 RdDram - Read from DRAM
// 3 WrDram - Write to DRAM
break;
case 0xC0010017: // IORRMask0-1
case 0xC0010019:
// 39-12 Mask27-0 - Address mask
// 11 V - Register enabled
break;
case 0xC001001A: // TOP_MEM
// 39-23 TOM16-0 - Top of Memory, accesses from this address onward are directed to mmio
ret = (uint64_t)m_msr_top_mem;
break;
case 0xC001001D: // TOP_MEM2
break;
case 0xC0010111: // SMM_BASE
// address of system management mode area
ret = (uint64_t)m_msr_smm_base;
break;
case 0xC0010113: // SMM_MASK
// 1 TValid - Enable TSeg SMRAM Range
// 0 AValid - Enable ASeg SMRAM Range
/* Access to the ASeg (a0000-bffff) depends on bit 0 of smm_mask
if the bit is 0 use the associated fixed mtrr
if the bit is 1
if smm is active
access goes to dram (wrmem 1 rdmem 1)
if smm not active
access goes to mmio (wrmem 0 rdmem 0) */
ret = m_msr_smm_mask;
break;
}
valid_msr = true;
return ret;
}
void athlonxp_device::opcode_wrmsr(uint64_t data, bool &valid_msr)
{
uint32_t offset = REG32(ECX);
switch (offset)
{
case 0x1b: // APIC_BASE
break;
case 0x17b: // MCG_CTL
break;
case 0x200: // MTRRphysBase0-7
case 0x201: // MTRRphysMask0-7
case 0x202:
case 0x203:
case 0x204:
case 0x205:
case 0x206:
case 0x207:
case 0x208:
case 0x209:
case 0x20a:
case 0x20b:
case 0x20c:
case 0x20d:
case 0x20e:
case 0x20f:
break;
case 0x2ff: // MTRRdefType
break;
case 0x250: // MTRRfix64K_00000
m_msr_mtrrfix[0] = data;
parse_mtrrfix(data, 0, 64);
break;
case 0x258: // MTRRfix16K_80000
m_msr_mtrrfix[1] = data;
parse_mtrrfix(data, 0x80000, 16);
break;
case 0x259: // MTRRfix16K_A0000
m_msr_mtrrfix[2] = data;
if (m_msr_smm_mask & 1)
{
if (m_smm)
data = 0x1818181818181818; // when smm is active
else
data = 0; // when smm is not active
}
parse_mtrrfix(data, 0xa0000, 16);
break;
case 0x268: // MTRRfix4K_C0000-F8000
case 0x269:
case 0x26a:
case 0x26b:
case 0x26c:
case 0x26d:
case 0x26e:
case 0x26f:
m_msr_mtrrfix[3 + offset - 0x268] = data;
parse_mtrrfix(data, 0xc0000 + (offset - 0x268) * 0x8000, 4);
break;
case 0x400: // MC0_CTL
break;
case 0x404: // MC1_CTL
break;
case 0x408: // MC2_CTL
break;
case 0x40c: // MC3_CTL
break;
case 0xC0010010: // SYS_CFG
m_msr_sys_cfg = data;
break;
case 0xC0010015: // HWCR
break;
case 0xC0010016: // IORRBase
case 0xC0010017: // IORRMask
case 0xC0010018:
case 0xC0010019:
break;
case 0xC001001A: // TOP_MEM
m_msr_top_mem = (offs_t)data;
break;
case 0xC0010111: // SMM_BASE
m_msr_smm_base = (offs_t)data;
m_smbase = m_msr_smm_base;
break;
case 0xC0010113: // SMM_MASK
m_msr_smm_mask = data;
if (m_msr_smm_mask & 1)
{
if (m_smm)
data = 0x1818181818181818; // when smm is active
else
data = 0; // when smm is not active
}
else
data = m_msr_mtrrfix[2];
parse_mtrrfix(data, 0xa0000, 16);
break;
}
valid_msr = true;
}

View File

@ -6,339 +6,6 @@
#ifndef __CYCLES_H__
#define __CYCLES_H__
enum X86_CYCLES
{
CYCLES_MOV_REG_REG,
CYCLES_MOV_REG_MEM,
CYCLES_MOV_MEM_REG,
CYCLES_MOV_IMM_REG,
CYCLES_MOV_IMM_MEM,
CYCLES_MOV_ACC_MEM,
CYCLES_MOV_MEM_ACC,
CYCLES_MOV_REG_SREG,
CYCLES_MOV_MEM_SREG,
CYCLES_MOV_SREG_REG,
CYCLES_MOV_SREG_MEM,
CYCLES_MOVSX_REG_REG,
CYCLES_MOVSX_MEM_REG,
CYCLES_MOVZX_REG_REG,
CYCLES_MOVZX_MEM_REG,
CYCLES_PUSH_RM,
CYCLES_PUSH_REG_SHORT,
CYCLES_PUSH_SREG,
CYCLES_PUSH_IMM,
CYCLES_PUSHA,
CYCLES_POP_RM,
CYCLES_POP_REG_SHORT,
CYCLES_POP_SREG,
CYCLES_POPA,
CYCLES_XCHG_REG_REG,
CYCLES_XCHG_REG_MEM,
CYCLES_IN,
CYCLES_IN_VAR,
CYCLES_OUT,
CYCLES_OUT_VAR,
CYCLES_LEA,
CYCLES_LDS,
CYCLES_LES,
CYCLES_LFS,
CYCLES_LGS,
CYCLES_LSS,
CYCLES_CLC,
CYCLES_CLD,
CYCLES_CLI,
CYCLES_CLTS,
CYCLES_CMC,
CYCLES_LAHF,
CYCLES_POPF,
CYCLES_PUSHF,
CYCLES_SAHF,
CYCLES_STC,
CYCLES_STD,
CYCLES_STI,
CYCLES_ALU_REG_REG,
CYCLES_ALU_REG_MEM,
CYCLES_ALU_MEM_REG,
CYCLES_ALU_IMM_REG,
CYCLES_ALU_IMM_MEM,
CYCLES_ALU_IMM_ACC,
CYCLES_INC_REG,
CYCLES_INC_MEM,
CYCLES_DEC_REG,
CYCLES_DEC_MEM,
CYCLES_CMP_REG_REG,
CYCLES_CMP_REG_MEM,
CYCLES_CMP_MEM_REG,
CYCLES_CMP_IMM_REG,
CYCLES_CMP_IMM_MEM,
CYCLES_CMP_IMM_ACC,
CYCLES_TEST_REG_REG,
CYCLES_TEST_REG_MEM,
CYCLES_TEST_IMM_REG,
CYCLES_TEST_IMM_MEM,
CYCLES_TEST_IMM_ACC,
CYCLES_NEG_REG,
CYCLES_NEG_MEM,
CYCLES_AAA,
CYCLES_AAS,
CYCLES_DAA,
CYCLES_DAS,
CYCLES_MUL8_ACC_REG,
CYCLES_MUL8_ACC_MEM,
CYCLES_MUL16_ACC_REG,
CYCLES_MUL16_ACC_MEM,
CYCLES_MUL32_ACC_REG,
CYCLES_MUL32_ACC_MEM,
CYCLES_IMUL8_ACC_REG,
CYCLES_IMUL8_ACC_MEM,
CYCLES_IMUL16_ACC_REG,
CYCLES_IMUL16_ACC_MEM,
CYCLES_IMUL32_ACC_REG,
CYCLES_IMUL32_ACC_MEM,
CYCLES_IMUL8_REG_REG,
CYCLES_IMUL8_REG_MEM,
CYCLES_IMUL16_REG_REG,
CYCLES_IMUL16_REG_MEM,
CYCLES_IMUL32_REG_REG,
CYCLES_IMUL32_REG_MEM,
CYCLES_IMUL16_REG_IMM_REG,
CYCLES_IMUL16_MEM_IMM_REG,
CYCLES_IMUL32_REG_IMM_REG,
CYCLES_IMUL32_MEM_IMM_REG,
CYCLES_DIV8_ACC_REG,
CYCLES_DIV8_ACC_MEM,
CYCLES_DIV16_ACC_REG,
CYCLES_DIV16_ACC_MEM,
CYCLES_DIV32_ACC_REG,
CYCLES_DIV32_ACC_MEM,
CYCLES_IDIV8_ACC_REG,
CYCLES_IDIV8_ACC_MEM,
CYCLES_IDIV16_ACC_REG,
CYCLES_IDIV16_ACC_MEM,
CYCLES_IDIV32_ACC_REG,
CYCLES_IDIV32_ACC_MEM,
CYCLES_AAD,
CYCLES_AAM,
CYCLES_CBW,
CYCLES_CWD,
CYCLES_ROTATE_REG,
CYCLES_ROTATE_MEM,
CYCLES_ROTATE_CARRY_REG,
CYCLES_ROTATE_CARRY_MEM,
CYCLES_SHLD_REG,
CYCLES_SHLD_MEM,
CYCLES_SHRD_REG,
CYCLES_SHRD_MEM,
CYCLES_NOT_REG,
CYCLES_NOT_MEM,
CYCLES_CMPS,
CYCLES_INS,
CYCLES_LODS,
CYCLES_MOVS,
CYCLES_OUTS,
CYCLES_SCAS,
CYCLES_STOS,
CYCLES_XLAT,
CYCLES_REP_CMPS_BASE,
CYCLES_REP_INS_BASE,
CYCLES_REP_LODS_BASE,
CYCLES_REP_MOVS_BASE,
CYCLES_REP_OUTS_BASE,
CYCLES_REP_SCAS_BASE,
CYCLES_REP_STOS_BASE,
CYCLES_REP_CMPS,
CYCLES_REP_INS,
CYCLES_REP_LODS,
CYCLES_REP_MOVS,
CYCLES_REP_OUTS,
CYCLES_REP_SCAS,
CYCLES_REP_STOS,
CYCLES_BSF_BASE,
CYCLES_BSF,
CYCLES_BSR_BASE,
CYCLES_BSR,
CYCLES_BT_IMM_REG,
CYCLES_BT_IMM_MEM,
CYCLES_BT_REG_REG,
CYCLES_BT_REG_MEM,
CYCLES_BTC_IMM_REG,
CYCLES_BTC_IMM_MEM,
CYCLES_BTC_REG_REG,
CYCLES_BTC_REG_MEM,
CYCLES_BTR_IMM_REG,
CYCLES_BTR_IMM_MEM,
CYCLES_BTR_REG_REG,
CYCLES_BTR_REG_MEM,
CYCLES_BTS_IMM_REG,
CYCLES_BTS_IMM_MEM,
CYCLES_BTS_REG_REG,
CYCLES_BTS_REG_MEM,
CYCLES_CALL, // E8
CYCLES_CALL_REG, // FF /2
CYCLES_CALL_MEM, // FF /2
CYCLES_CALL_INTERSEG, // 9A
CYCLES_CALL_REG_INTERSEG, // FF /3
CYCLES_CALL_MEM_INTERSEG, // FF /3
CYCLES_JMP_SHORT, // EB
CYCLES_JMP, // E9
CYCLES_JMP_REG, // FF /4
CYCLES_JMP_MEM, // FF /4
CYCLES_JMP_INTERSEG, // EA
CYCLES_JMP_REG_INTERSEG, // FF /5
CYCLES_JMP_MEM_INTERSEG, // FF /5
CYCLES_RET, // C3
CYCLES_RET_IMM, // C2
CYCLES_RET_INTERSEG, // CB
CYCLES_RET_IMM_INTERSEG, // CA
CYCLES_JCC_DISP8,
CYCLES_JCC_FULL_DISP,
CYCLES_JCC_DISP8_NOBRANCH,
CYCLES_JCC_FULL_DISP_NOBRANCH,
CYCLES_JCXZ,
CYCLES_JCXZ_NOBRANCH,
CYCLES_LOOP,
CYCLES_LOOPZ,
CYCLES_LOOPNZ,
CYCLES_SETCC_REG,
CYCLES_SETCC_MEM,
CYCLES_ENTER,
CYCLES_LEAVE,
CYCLES_INT,
CYCLES_INT3,
CYCLES_INTO_OF1,
CYCLES_INTO_OF0,
CYCLES_BOUND_IN_RANGE,
CYCLES_BOUND_OUT_RANGE,
CYCLES_IRET,
CYCLES_HLT,
CYCLES_MOV_REG_CR0,
CYCLES_MOV_REG_CR2,
CYCLES_MOV_REG_CR3,
CYCLES_MOV_CR_REG,
CYCLES_MOV_REG_DR0_3,
CYCLES_MOV_REG_DR6_7,
CYCLES_MOV_DR6_7_REG,
CYCLES_MOV_DR0_3_REG,
CYCLES_MOV_REG_TR6_7,
CYCLES_MOV_TR6_7_REG,
CYCLES_NOP,
CYCLES_WAIT,
CYCLES_ARPL_REG,
CYCLES_ARPL_MEM,
CYCLES_LAR_REG,
CYCLES_LAR_MEM,
CYCLES_LGDT,
CYCLES_LIDT,
CYCLES_LLDT_REG,
CYCLES_LLDT_MEM,
CYCLES_LMSW_REG,
CYCLES_LMSW_MEM,
CYCLES_LSL_REG,
CYCLES_LSL_MEM,
CYCLES_LTR_REG,
CYCLES_LTR_MEM,
CYCLES_SGDT,
CYCLES_SIDT,
CYCLES_SLDT_REG,
CYCLES_SLDT_MEM,
CYCLES_SMSW_REG,
CYCLES_SMSW_MEM,
CYCLES_STR_REG,
CYCLES_STR_MEM,
CYCLES_VERR_REG,
CYCLES_VERR_MEM,
CYCLES_VERW_REG,
CYCLES_VERW_MEM,
CYCLES_LOCK,
CYCLES_BSWAP,
CYCLES_CMPXCHG8B,
CYCLES_CMPXCHG,
CYCLES_CPUID,
CYCLES_CPUID_EAX1,
CYCLES_INVD,
CYCLES_XADD,
CYCLES_RDTSC,
CYCLES_RSM,
CYCLES_RDMSR,
CYCLES_FABS,
CYCLES_FADD,
CYCLES_FBLD,
CYCLES_FBSTP,
CYCLES_FCHS,
CYCLES_FCLEX,
CYCLES_FCOM,
CYCLES_FCOS,
CYCLES_FDECSTP,
CYCLES_FDISI,
CYCLES_FDIV,
CYCLES_FDIVR,
CYCLES_FENI,
CYCLES_FFREE,
CYCLES_FIADD,
CYCLES_FICOM,
CYCLES_FIDIV,
CYCLES_FILD,
CYCLES_FIMUL,
CYCLES_FINCSTP,
CYCLES_FINIT,
CYCLES_FIST,
CYCLES_FISUB,
CYCLES_FLD,
CYCLES_FLDZ,
CYCLES_FLD1,
CYCLES_FLDL2E,
CYCLES_FLDL2T,
CYCLES_FLDLG2,
CYCLES_FLDLN2,
CYCLES_FLDPI,
CYCLES_FLDCW,
CYCLES_FLDENV,
CYCLES_FMUL,
CYCLES_FNOP,
CYCLES_FPATAN,
CYCLES_FPREM,
CYCLES_FPREM1,
CYCLES_FPTAN,
CYCLES_FRNDINT,
CYCLES_FRSTOR,
CYCLES_FSAVE,
CYCLES_FSCALE,
CYCLES_FSETPM,
CYCLES_FSIN,
CYCLES_FSINCOS,
CYCLES_FSQRT,
CYCLES_FST,
CYCLES_FSTCW,
CYCLES_FSTENV,
CYCLES_FSTSW,
CYCLES_FSUB,
CYCLES_FSUBR,
CYCLES_FTST,
CYCLES_FUCOM,
CYCLES_FXAM,
CYCLES_FXCH,
CYCLES_FXTRACT,
CYCLES_FYL2X,
CYCLES_FYL2XPI,
CYCLES_CMPXCHG_REG_REG_T,
CYCLES_CMPXCHG_REG_REG_F,
CYCLES_CMPXCHG_REG_MEM_T,
CYCLES_CMPXCHG_REG_MEM_F,
CYCLES_XADD_REG_REG,
CYCLES_XADD_REG_MEM,
CYCLES_NUM_OPCODES
};
#define CPU_CYCLES_I386 0
#define CPU_CYCLES_I486 1
#define CPU_CYCLES_PENTIUM 2
#define CPU_CYCLES_MEDIAGX 3
struct X86_CYCLE_TABLE
{
X86_CYCLES op;

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,6 @@
#include "divtlb.h"
#include "i386dasm.h"
#include "cache.h"
#define INPUT_LINE_A20 1
#define INPUT_LINE_SMI 2
@ -95,13 +94,6 @@ protected:
virtual u16 mem_pr16(offs_t address) { return macache32->read_word(address); }
virtual u32 mem_pr32(offs_t address) { return macache32->read_dword(address); }
virtual u8 mem_prd8(offs_t address) { return m_program->read_byte(address); }
virtual u16 mem_prd16(offs_t address) { return m_program->read_word(address); }
virtual u32 mem_prd32(offs_t address) { return m_program->read_dword(address); }
virtual void mem_pwd8(offs_t address, u8 data) { m_program->write_byte(address, data); }
virtual void mem_pwd16(offs_t address, u16 data) { m_program->write_word(address, data); }
virtual void mem_pwd32(offs_t address, u32 data) { m_program->write_dword(address, data); }
address_space_config m_program_config;
address_space_config m_io_config;
@ -391,27 +383,32 @@ protected:
void register_state_i386();
void register_state_i386_x87();
void register_state_i386_x87_xmm();
inline uint32_t i386_translate(int segment, uint32_t ip, int rwn);
uint32_t i386_translate(int segment, uint32_t ip, int rwn);
inline vtlb_entry get_permissions(uint32_t pte, int wp);
bool i386_translate_address(int intention, offs_t *address, vtlb_entry *entry);
inline bool translate_address(int pl, int type, uint32_t *address, uint32_t *error);
inline void CHANGE_PC(uint32_t pc);
bool translate_address(int pl, int type, uint32_t *address, uint32_t *error);
void CHANGE_PC(uint32_t pc);
inline void NEAR_BRANCH(int32_t offs);
inline uint8_t FETCH();
inline uint16_t FETCH16();
inline uint32_t FETCH32();
inline uint8_t READ8(uint32_t ea);
inline uint16_t READ16(uint32_t ea);
inline uint32_t READ32(uint32_t ea);
inline uint64_t READ64(uint32_t ea);
inline uint8_t READ8PL0(uint32_t ea);
inline uint16_t READ16PL0(uint32_t ea);
inline uint32_t READ32PL0(uint32_t ea);
inline uint8_t READ8(uint32_t ea) { return READ8PL(ea, m_CPL); }
inline uint16_t READ16(uint32_t ea) { return READ16PL(ea, m_CPL); }
inline uint32_t READ32(uint32_t ea) { return READ32PL(ea, m_CPL); }
inline uint64_t READ64(uint32_t ea) { return READ64PL(ea, m_CPL); }
virtual uint8_t READ8PL(uint32_t ea, uint8_t privilege);
virtual uint16_t READ16PL(uint32_t ea, uint8_t privilege);
virtual uint32_t READ32PL(uint32_t ea, uint8_t privilege);
virtual uint64_t READ64PL(uint32_t ea, uint8_t privilege);
inline void WRITE_TEST(uint32_t ea);
inline void WRITE8(uint32_t ea, uint8_t value);
inline void WRITE16(uint32_t ea, uint16_t value);
inline void WRITE32(uint32_t ea, uint32_t value);
inline void WRITE64(uint32_t ea, uint64_t value);
inline void WRITE8(uint32_t ea, uint8_t value) { WRITE8PL(ea, m_CPL, value); }
inline void WRITE16(uint32_t ea, uint16_t value) { WRITE16PL(ea, m_CPL, value); }
inline void WRITE32(uint32_t ea, uint32_t value) { WRITE32PL(ea, m_CPL, value); }
inline void WRITE64(uint32_t ea, uint64_t value) { WRITE64PL(ea, m_CPL, value); }
virtual void WRITE8PL(uint32_t ea, uint8_t privilege, uint8_t value);
virtual void WRITE16PL(uint32_t ea, uint8_t privilege, uint16_t value);
virtual void WRITE32PL(uint32_t ea, uint8_t privilege, uint32_t value);
virtual void WRITE64PL(uint32_t ea, uint8_t privilege, uint64_t value);
inline uint8_t OR8(uint8_t dst, uint8_t src);
inline uint16_t OR16(uint16_t dst, uint16_t src);
inline uint32_t OR32(uint32_t dst, uint32_t src);
@ -445,10 +442,10 @@ protected:
inline void check_ioperm(offs_t port, uint8_t mask);
inline uint8_t READPORT8(offs_t port);
inline void WRITEPORT8(offs_t port, uint8_t value);
inline uint16_t READPORT16(offs_t port);
inline void WRITEPORT16(offs_t port, uint16_t value);
inline uint32_t READPORT32(offs_t port);
inline void WRITEPORT32(offs_t port, uint32_t value);
virtual uint16_t READPORT16(offs_t port);
virtual void WRITEPORT16(offs_t port, uint16_t value);
virtual uint32_t READPORT32(offs_t port);
virtual void WRITEPORT32(offs_t port, uint32_t value);
uint32_t i386_load_protected_mode_segment(I386_SREG *seg, uint64_t *desc );
void i386_load_call_gate(I386_CALL_GATE *gate);
void i386_set_descriptor_accessed(uint16_t selector);
@ -490,7 +487,7 @@ protected:
void i386_decode_four_byte38f3();
uint8_t read8_debug(uint32_t ea, uint8_t *data);
uint32_t i386_get_debug_desc(I386_SREG *seg);
inline void CYCLES(int x);
void CYCLES(int x);
inline void CYCLES_RM(int modrm, int r, int m);
uint8_t i386_shift_rotate8(uint8_t modrm, uint32_t value, uint8_t shift);
void i386_adc_rm8_r8();
@ -1524,6 +1521,17 @@ protected:
virtual u8 mem_pr8(offs_t address) override { return macache16->read_byte(address); };
virtual u16 mem_pr16(offs_t address) override { return macache16->read_word(address); };
virtual u32 mem_pr32(offs_t address) override { return macache16->read_dword(address); };
virtual uint16_t READ16PL(uint32_t ea, uint8_t privilege) override;
virtual uint32_t READ32PL(uint32_t ea, uint8_t privilege) override;
virtual uint64_t READ64PL(uint32_t ea, uint8_t privilege) override;
virtual void WRITE16PL(uint32_t ea, uint8_t privilege, uint16_t value) override;
virtual void WRITE32PL(uint32_t ea, uint8_t privilege, uint32_t value) override;
virtual void WRITE64PL(uint32_t ea, uint8_t privilege, uint64_t value) override;
virtual uint16_t READPORT16(offs_t port) override;
virtual void WRITEPORT16(offs_t port, uint16_t value) override;
virtual uint32_t READPORT32(offs_t port) override;
virtual void WRITEPORT32(offs_t port, uint32_t value) override;
};
class i486_device : public i386_device
@ -1632,64 +1640,6 @@ protected:
};
class athlonxp_device : public pentium_device
{
public:
// construction/destruction
athlonxp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
virtual void opcode_cpuid() override;
virtual uint64_t opcode_rdmsr(bool &valid_msr) override;
virtual void opcode_wrmsr(uint64_t data, bool &valid_msr) override;
virtual void cache_writeback() override;
virtual void cache_invalidate() override;
virtual void cache_clean() override;
virtual void device_start() override;
virtual void device_reset() override;
virtual void enter_smm() override;
virtual void leave_smm() override;
virtual u8 mem_pr8(offs_t address) override { return opcode_read_cache<u8, NATIVE_ENDIAN_VALUE_LE_BE(0, 3)>(address); }
virtual u16 mem_pr16(offs_t address) override { return opcode_read_cache<u16, NATIVE_ENDIAN_VALUE_LE_BE(0, 2)>(address); }
virtual u32 mem_pr32(offs_t address) override { return opcode_read_cache<u32, 0>(address); }
virtual u8 mem_prd8(offs_t address) override { return program_read_cache<u8, NATIVE_ENDIAN_VALUE_LE_BE(0, 3)>(address); }
virtual u16 mem_prd16(offs_t address) override { return program_read_cache<u16, NATIVE_ENDIAN_VALUE_LE_BE(0, 2)>(address); }
virtual u32 mem_prd32(offs_t address) override { return program_read_cache<u32, 0>(address); }
virtual void mem_pwd8(offs_t address, u8 data) override { program_write_cache<u8, NATIVE_ENDIAN_VALUE_LE_BE(0, 3)>(address, data); }
virtual void mem_pwd16(offs_t address, u16 data) override { program_write_cache<u16, NATIVE_ENDIAN_VALUE_LE_BE(0, 2)>(address, data); }
virtual void mem_pwd32(offs_t address, u32 data) override { program_write_cache<u32, 0>(address, data); }
// device_memory_interface override
virtual space_config_vector memory_space_config() const override;
private:
void parse_mtrrfix(u64 mtrr, offs_t base, int kblock);
inline int check_cacheable(offs_t address);
template <int wr> int address_mode(offs_t address);
template <class dt, offs_t xorle> dt opcode_read_cache(offs_t address);
template <class dt, offs_t xorle> dt program_read_cache(offs_t address);
template <class dt, offs_t xorle> void program_write_cache(offs_t address, dt data);
DECLARE_READ32_MEMBER(debug_read_memory);
address_space_config m_data_config;
address_space *m_data;
address_space_config m_opcodes_config;
address_space *m_opcodes;
memory_access_cache<2, 0, ENDIANNESS_LITTLE> *mmacache32;
uint8_t m_processor_name_string[48];
offs_t m_msr_top_mem;
uint64_t m_msr_sys_cfg;
offs_t m_msr_smm_base;
uint64_t m_msr_smm_mask;
uint64_t m_msr_mtrrfix[11];
uint8_t m_memory_ranges_1m[1024 / 4];
cpucache<17, 9, Cache2Way, CacheLineBytes64> cache; // 512 sets, 2 ways (cachelines per set), 64 bytes per cacheline
};
class pentium4_device : public pentium_device
{
public:
@ -1714,7 +1664,6 @@ DECLARE_DEVICE_TYPE(MEDIAGX, mediagx_device)
DECLARE_DEVICE_TYPE(PENTIUM_PRO, pentium_pro_device)
DECLARE_DEVICE_TYPE(PENTIUM2, pentium2_device)
DECLARE_DEVICE_TYPE(PENTIUM3, pentium3_device)
DECLARE_DEVICE_TYPE(ATHLONXP, athlonxp_device)
DECLARE_DEVICE_TYPE(PENTIUM4, pentium4_device)
#endif // MAME_CPU_I386_I386_H

View File

@ -1,26 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett
#define OP_I386 0x1
#define OP_FPU 0x2
#define OP_I486 0x4
#define OP_PENTIUM 0x8
#define OP_MMX 0x10
#define OP_PPRO 0x20
#define OP_SSE 0x40
#define OP_SSE2 0x80
#define OP_SSE3 0x100
#define OP_CYRIX 0x8000
#define OP_2BYTE 0x80000000
#define OP_3BYTE66 0x40000000
#define OP_3BYTEF2 0x20000000
#define OP_3BYTEF3 0x10000000
#define OP_3BYTE38 0x08000000
#define OP_3BYTE3A 0x04000000
#define OP_4BYTE3866 0x02000000
#define OP_4BYTE3A66 0x01000000
#define OP_4BYTE38F2 0x00800000
#define OP_4BYTE3AF2 0x00400000
#define OP_4BYTE38F3 0x00200000
const i386_device::X86_OPCODE i386_device::s_x86_opcode_table[] =
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@
#include "emu.h"
#include "cpu/i386/i386.h"
#include "cpu/i386/athlon.h"
#include "machine/pci.h"
#include "machine/pci-ide.h"
#include "machine/intelfsh.h"