From 03e88d66960cf303d2cbb8704593346ada9f99ea Mon Sep 17 00:00:00 2001 From: yz70s Date: Sun, 7 Apr 2019 18:45:50 +0200 Subject: [PATCH] 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 --- src/devices/cpu/i386/cpuidmsrs.hxx | 4 + src/devices/cpu/i386/i386.cpp | 154 ++++++++++++++++++----------- src/devices/cpu/i386/i386.h | 15 ++- 3 files changed, 113 insertions(+), 60 deletions(-) diff --git a/src/devices/cpu/i386/cpuidmsrs.hxx b/src/devices/cpu/i386/cpuidmsrs.hxx index 842ff85b4b2..8b02d7828cd 100644 --- a/src/devices/cpu/i386/cpuidmsrs.hxx +++ b/src/devices/cpu/i386/cpuidmsrs.hxx @@ -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; diff --git a/src/devices/cpu/i386/i386.cpp b/src/devices/cpu/i386/i386.cpp index 22123c46387..97dd5e5a8b6 100644 --- a/src/devices/cpu/i386/i386.cpp +++ b/src/devices/cpu/i386/i386.cpp @@ -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 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(address); + if (data) + return *(u32 *)(data + offset); + } + if (address_mode<1>(address)) + m = m_data; + return m->read_dword(address); +} + template 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 @@ -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 @@ -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); } } diff --git a/src/devices/cpu/i386/i386.h b/src/devices/cpu/i386/i386.h index 6fd0dc04266..e3182fcfb81 100644 --- a/src/devices/cpu/i386/i386.h +++ b/src/devices/cpu/i386/i386.h @@ -1655,15 +1655,28 @@ protected: virtual void mem_pwd16(offs_t address, u16 data) override { program_write_cache(address, data); } virtual void mem_pwd32(offs_t address, u32 data) override { program_write_cache(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 address_mode(offs_t address); template dt opcode_read_cache(offs_t address); template dt program_read_cache(offs_t address); template 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