i386.cpp: athlon xp updates to memory access (nw)

Now athlon xp supports WrMem and RdMem bits in fixed range MTRRs
Accesses to the first megabyte can be directed to system memory (ram) or
memory-mapped-io (mmio) (the pci bus)
Above 1mb accesses below the top_mem MSR address ram the others mmio
At reset everyting is directed to mmio
Addresss spaces work in the following way
AS_PROGRAM is used for ram
AS_DATA is used for mmio
AS_OPCODES is used by the debugger disassembler and in memory views to
look at the memory contents from the point of view of the
microprocessor, including the cache
Also some class members have been added to the save state
This commit is contained in:
yz70s 2019-04-07 18:45:50 +02:00
parent 702b45b1bc
commit 03e88d6696
3 changed files with 113 additions and 60 deletions

View File

@ -347,6 +347,7 @@ uint64_t athlonxp_device::opcode_rdmsr(bool &valid_msr)
// 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;
@ -363,6 +364,7 @@ uint64_t athlonxp_device::opcode_rdmsr(bool &valid_msr)
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;
@ -434,6 +436,7 @@ void athlonxp_device::opcode_wrmsr(uint64_t data, bool &valid_msr)
case 0x40c: // MC3_CTL
break;
case 0xC0010010: // SYS_CFG
m_msr_sys_cfg = data;
break;
case 0xC0010015: // HWCR
break;
@ -443,6 +446,7 @@ void athlonxp_device::opcode_wrmsr(uint64_t data, bool &valid_msr)
case 0xC0010019:
break;
case 0xC001001A: // TOP_MEM
m_msr_top_mem = (offs_t)data;
break;
case 0xC0010113: // SMM_MASK
break;

View File

@ -133,6 +133,8 @@ pentium3_device::pentium3_device(const machine_config &mconfig, const char *tag,
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);
@ -4692,11 +4694,22 @@ 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_mtrrfix));
save_item(NAME(m_memory_ranges_1m));
}
void athlonxp_device::device_reset()
@ -4745,7 +4758,9 @@ void athlonxp_device::device_reset()
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; // change the 0 to 6 to test the cache just after reset
m_memory_ranges_1m[n] = 0;
m_msr_top_mem = 1024 * 1024;
m_msr_sys_cfg = 0;
m_cpuid_max_input_value_eax = 0x01;
m_cpu_version = REG32(EDX);
@ -4756,6 +4771,16 @@ void athlonxp_device::device_reset()
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::parse_mtrrfix(u64 mtrr, offs_t base, int kblock)
{
int nb = kblock / 4;
@ -4788,11 +4813,48 @@ int athlonxp_device::check_cacheable(offs_t address)
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)
@ -4814,31 +4876,21 @@ dt athlonxp_device::opcode_read_cache(offs_t address)
offs_t old_address = cache.old();
for (int w = 0; w < 64; w += 4)
macache32->write_dword(old_address + w, *(u32 *)(data + w));
m->write_dword(old_address + w, *(u32 *)(data + w));
}
for (int r = 0; r < 64; r += 4)
*(u32 *)(data + r) = macache32->read_dword(address + r);
*(u32 *)(data + r) = m->read_dword(address + r);
return *(dt *)(data + offset);
}
else
{
if (sizeof(dt) == 1)
return macache32->read_byte(address);
else if (sizeof(dt) == 2)
return macache32->read_word(address);
else
return macache32->read_dword(address);
}
}
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
{
if (sizeof(dt) == 1)
return macache32->read_byte(address);
else if (sizeof(dt) == 2)
return macache32->read_word(address);
else
return macache32->read_dword(address);
}
return m->read_dword(address);
}
template <class dt, offs_t xorle>
@ -4846,6 +4898,7 @@ dt athlonxp_device::program_read_cache(offs_t address)
{
int mode = check_cacheable(address);
bool nocache = false;
address_space *m = m_program;
u8 *data;
if ((mode & 7) == 0)
@ -4867,31 +4920,21 @@ dt athlonxp_device::program_read_cache(offs_t address)
offs_t old_address = cache.old();
for (int w = 0; w < 64; w += 4)
m_program->write_dword(old_address + w, *(u32 *)(data + w));
m->write_dword(old_address + w, *(u32 *)(data + w));
}
for (int r = 0; r < 64; r += 4)
*(u32 *)(data + r) = m_program->read_dword(address + r);
*(u32 *)(data + r) = m->read_dword(address + r);
return *(dt *)(data + offset);
}
else
{
if (sizeof(dt) == 1)
return m_program->read_byte(address);
else if (sizeof(dt) == 2)
return m_program->read_word(address);
else
return m_program->read_dword(address);
}
}
if (address_mode<1>(address))
m = m_data;
if (sizeof(dt) == 1)
return m->read_byte(address);
else if (sizeof(dt) == 2)
return m->read_word(address);
else
{
if (sizeof(dt) == 1)
return m_program->read_byte(address);
else if (sizeof(dt) == 2)
return m_program->read_word(address);
else
return m_program->read_dword(address);
}
return m->read_dword(address);
}
template <class dt, offs_t xorle>
@ -4899,6 +4942,7 @@ void athlonxp_device::program_write_cache(offs_t address, dt data)
{
int mode = check_cacheable(address);
bool nocache = false;
address_space *m = m_program;
u8 *dataw;
if ((mode & 7) == 0)
@ -4923,36 +4967,28 @@ void athlonxp_device::program_write_cache(offs_t address, dt data)
offs_t old_address = cache.old();
for (int w = 0; w < 64; w += 4)
m_program->write_dword(old_address + w, *(u32 *)(dataw + w));
m->write_dword(old_address + w, *(u32 *)(dataw + w));
}
for (int r = 0; r < 64; r += 4)
*(u32 *)(dataw + r) = m_program->read_dword(address + r);
*(u32 *)(dataw + r) = m->read_dword(address + r);
*(dt *)(dataw + offset) = data;
}
else
{
if (sizeof(dt) == 1)
m_program->write_byte(address, data);
else if (sizeof(dt) == 2)
m_program->write_word(address, data);
else
m_program->write_dword(address, data);
return;
}
}
if (address_mode<0>(address))
m = m_data;
if (sizeof(dt) == 1)
m->write_byte(address, data);
else if (sizeof(dt) == 2)
m->write_word(address, data);
else
{
if (sizeof(dt) == 1)
m_program->write_byte(address, data);
else if (sizeof(dt) == 2)
m_program->write_word(address, data);
else
m_program->write_dword(address, data);
}
m->write_dword(address, data);
}
void athlonxp_device::cache_writeback()
{
// dirty cachelines are written back to memory
address_space *m = m_program;
u32 base;
u8 *data;
@ -4960,7 +4996,7 @@ void athlonxp_device::cache_writeback()
while (data != nullptr)
{
for (int w = 0; w < 64; w += 4)
m_program->write_dword(base + w, *(u32 *)(data + w));
m->write_dword(base + w, *(u32 *)(data + w));
data = cache.next_dirty(base, false);
}
}

View File

@ -1655,15 +1655,28 @@ protected:
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);
int check_cacheable(offs_t address);
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;
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