From 95c50fed36cac898137dd8a8677c911705d9d5bb Mon Sep 17 00:00:00 2001 From: yz70s Date: Fri, 2 Nov 2018 07:58:38 +0100 Subject: i386.cpp: add virtual methods for cpuid and msr instructions (nw) - add virtual methods opcode_cpuid opcode_rdmsr opcode_wrmsr - default implementations in class i386_device log an error message - derive Pentium MMX, Pentium II, Pentium III classes from pentium_pro_device - remove pentium_msr_* p6_msr_* piv_msr_* MSR_READ MSR_WRITE routines and call virtual methods instead - the routine pentium_rdmsr modifies the registers only if the msr is valid --- src/devices/cpu/i386/i386.cpp | 209 +++++++++++++++++++++++++++++++++++- src/devices/cpu/i386/i386.h | 28 +++-- src/devices/cpu/i386/i386priv.h | 223 --------------------------------------- src/devices/cpu/i386/i486ops.hxx | 3 +- src/devices/cpu/i386/pentops.hxx | 22 ++-- 5 files changed, 237 insertions(+), 248 deletions(-) diff --git a/src/devices/cpu/i386/i386.cpp b/src/devices/cpu/i386/i386.cpp index 06fbfca3fb5..9952755dc22 100644 --- a/src/devices/cpu/i386/i386.cpp +++ b/src/devices/cpu/i386/i386.cpp @@ -99,26 +99,31 @@ mediagx_device::mediagx_device(const machine_config &mconfig, const char *tag, d } pentium_pro_device::pentium_pro_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : pentium_device(mconfig, PENTIUM_PRO, tag, owner, clock) + : pentium_pro_device(mconfig, PENTIUM_PRO, tag, owner, clock) +{ +} + +pentium_pro_device::pentium_pro_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : pentium_device(mconfig, type, tag, owner, clock) { } pentium_mmx_device::pentium_mmx_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : pentium_device(mconfig, PENTIUM_MMX, tag, owner, clock) + : pentium_pro_device(mconfig, PENTIUM_MMX, tag, owner, clock) { // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large set_vtlb_dynamic_entries(96); } pentium2_device::pentium2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : pentium_device(mconfig, PENTIUM2, tag, owner, clock) + : pentium_pro_device(mconfig, PENTIUM2, tag, owner, clock) { // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large set_vtlb_dynamic_entries(96); } pentium3_device::pentium3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : pentium_device(mconfig, PENTIUM3, tag, owner, clock) + : pentium_pro_device(mconfig, PENTIUM3, tag, owner, clock) { // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large set_vtlb_dynamic_entries(96); @@ -4039,6 +4044,24 @@ std::unique_ptr i386_device::create_disassembler() return std::make_unique(this); } +void i386_device::opcode_cpuid() +{ + logerror("CPUID called with unsupported EAX=%08x at %08x!\n", REG32(EAX), m_eip); +} + +uint64_t i386_device::opcode_rdmsr(bool &valid_msr) +{ + valid_msr = false; + logerror("RDMSR called with unsupported ECX=%08x at %08x!\n", REG32(ECX), m_eip); + return -1; +} + +void i386_device::opcode_wrmsr(uint64_t data, bool &valid_msr) +{ + valid_msr = false; + logerror("WRMSR called with unsupported ECX=%08x (%08x%08x) at %08x!\n", REG32(ECX), (uint32_t)(data >> 32), (uint32_t)data, m_eip); +} + /*****************************************************************************/ /* Intel 486 */ @@ -4177,6 +4200,98 @@ void pentium_device::device_reset() CHANGE_PC(m_eip); } +uint64_t pentium_device::opcode_rdmsr(bool &valid_msr) +{ + uint32_t offset = REG32(ECX); + + switch (offset) + { + // Machine Check Exception (TODO) + case 0x00: + valid_msr = true; + popmessage("RDMSR: Reading P5_MC_ADDR"); + return 0; + case 0x01: + valid_msr = true; + popmessage("RDMSR: Reading P5_MC_TYPE"); + return 0; + // Time Stamp Counter + case 0x10: + valid_msr = true; + popmessage("RDMSR: Reading TSC"); + return m_tsc; + // Event Counters (TODO) + case 0x11: // CESR + valid_msr = true; + popmessage("RDMSR: Reading CESR"); + return 0; + case 0x12: // CTR0 + valid_msr = true; + return m_perfctr[0]; + case 0x13: // CTR1 + valid_msr = true; + return m_perfctr[1]; + default: + if (!(offset & ~0xf)) // 2-f are test registers + { + valid_msr = true; + logerror("RDMSR: Reading test MSR %x", offset); + return 0; + } + logerror("RDMSR: invalid P5 MSR read %08x at %08x\n", offset, m_pc - 2); + valid_msr = false; + return 0; + } + return -1; +} + +void pentium_device::opcode_wrmsr(uint64_t data, bool &valid_msr) +{ + uint32_t offset = REG32(ECX); + + switch (offset) + { + // Machine Check Exception (TODO) + case 0x00: + popmessage("WRMSR: Writing P5_MC_ADDR"); + valid_msr = true; + break; + case 0x01: + popmessage("WRMSR: Writing P5_MC_TYPE"); + valid_msr = true; + break; + // Time Stamp Counter + case 0x10: + m_tsc = data; + popmessage("WRMSR: Writing to TSC"); + valid_msr = true; + break; + // Event Counters (TODO) + case 0x11: // CESR + popmessage("WRMSR: Writing to CESR"); + valid_msr = true; + break; + case 0x12: // CTR0 + m_perfctr[0] = data; + valid_msr = true; + break; + case 0x13: // CTR1 + m_perfctr[1] = data; + valid_msr = true; + break; + default: + if (!(offset & ~0xf)) // 2-f are test registers + { + valid_msr = true; + logerror("WRMSR: Writing test MSR %x", offset); + break; + } + logerror("WRMSR: invalid MSR write %08x (%08x%08x) at %08x\n", offset, (uint32_t)(data >> 32), (uint32_t)data, m_pc - 2); + valid_msr = false; + break; + } +} + /*****************************************************************************/ /* Cyrix MediaGX */ @@ -4314,6 +4429,69 @@ void pentium_pro_device::device_reset() CHANGE_PC(m_eip); } +uint64_t pentium_pro_device::opcode_rdmsr(bool &valid_msr) +{ + uint32_t offset = REG32(ECX); + + switch (offset) + { + // Machine Check Exception (TODO) + case 0x00: + valid_msr = true; + popmessage("RDMSR: Reading P5_MC_ADDR"); + return 0; + case 0x01: + valid_msr = true; + popmessage("RDMSR: Reading P5_MC_TYPE"); + return 0; + // Time Stamp Counter + case 0x10: + valid_msr = true; + popmessage("RDMSR: Reading TSC"); + return m_tsc; + // Performance Counters (TODO) + case 0xc1: // PerfCtr0 + valid_msr = true; + return m_perfctr[0]; + case 0xc2: // PerfCtr1 + valid_msr = true; + return m_perfctr[1]; + default: + logerror("RDMSR: unimplemented register called %08x at %08x\n", offset, m_pc - 2); + valid_msr = true; + return 0; + } + return -1; +} + +void pentium_pro_device::opcode_wrmsr(uint64_t data, bool &valid_msr) +{ + uint32_t offset = REG32(ECX); + + switch (offset) + { + // Time Stamp Counter + case 0x10: + m_tsc = data; + popmessage("WRMSR: Writing to TSC"); + valid_msr = true; + break; + // Performance Counters (TODO) + case 0xc1: // PerfCtr0 + m_perfctr[0] = data; + valid_msr = true; + break; + case 0xc2: // PerfCtr1 + m_perfctr[1] = data; + valid_msr = true; + break; + default: + logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n", offset, (uint32_t)(data >> 32), (uint32_t)data, m_pc - 2); + valid_msr = true; + break; + } +} + /*****************************************************************************/ /* Intel Pentium MMX */ @@ -4655,3 +4833,26 @@ void pentium4_device::device_reset() CHANGE_PC(m_eip); } + +uint64_t pentium4_device::opcode_rdmsr(bool &valid_msr) +{ + switch (REG32(ECX)) + { + default: + logerror("RDMSR: unimplemented register called %08x at %08x\n", REG32(ECX), m_pc - 2); + valid_msr = true; + return 0; + } + return -1; +} + +void pentium4_device::opcode_wrmsr(uint64_t data, bool &valid_msr) +{ + switch (REG32(ECX)) + { + default: + logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n", REG32(ECX), (uint32_t)(data >> 32), (uint32_t)data, m_pc - 2); + valid_msr = true; + break; + } +} diff --git a/src/devices/cpu/i386/i386.h b/src/devices/cpu/i386/i386.h index 70db1238b8f..340e7a0c256 100644 --- a/src/devices/cpu/i386/i386.h +++ b/src/devices/cpu/i386/i386.h @@ -77,6 +77,12 @@ protected: virtual std::unique_ptr create_disassembler() override; virtual int get_mode() const override; + // routines for opcodes whose operation can vary between cpu models + // default implementations just log an error message + virtual void opcode_cpuid(); + virtual uint64_t opcode_rdmsr(bool &valid_msr); + virtual void opcode_wrmsr(uint64_t data, bool &valid_msr); + address_space_config m_program_config; address_space_config m_io_config; @@ -425,14 +431,6 @@ protected: 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); - uint64_t pentium_msr_read(uint32_t offset,uint8_t *valid_msr); - void pentium_msr_write(uint32_t offset, uint64_t data, uint8_t *valid_msr); - uint64_t p6_msr_read(uint32_t offset,uint8_t *valid_msr); - void p6_msr_write(uint32_t offset, uint64_t data, uint8_t *valid_msr); - uint64_t piv_msr_read(uint32_t offset,uint8_t *valid_msr); - void piv_msr_write(uint32_t offset, uint64_t data, uint8_t *valid_msr); - inline uint64_t MSR_READ(uint32_t offset,uint8_t *valid_msr); - inline void MSR_WRITE(uint32_t offset, uint64_t data, uint8_t *valid_msr); 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); @@ -1542,6 +1540,8 @@ protected: virtual bool execute_input_edge_triggered(int inputnum) const override { return inputnum == INPUT_LINE_NMI || inputnum == INPUT_LINE_SMI; } virtual void execute_set_input(int inputnum, int state) override; + virtual uint64_t opcode_rdmsr(bool &valid_msr) override; + virtual void opcode_wrmsr(uint64_t data, bool &valid_msr) override; virtual void device_start() override; virtual void device_reset() override; }; @@ -1566,12 +1566,16 @@ public: pentium_pro_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: + pentium_pro_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual uint64_t opcode_rdmsr(bool &valid_msr) override; + virtual void opcode_wrmsr(uint64_t data, bool &valid_msr) override; virtual void device_start() override; virtual void device_reset() override; }; -class pentium_mmx_device : public pentium_device +class pentium_mmx_device : public pentium_pro_device { public: // construction/destruction @@ -1583,7 +1587,7 @@ protected: }; -class pentium2_device : public pentium_device +class pentium2_device : public pentium_pro_device { public: // construction/destruction @@ -1595,7 +1599,7 @@ protected: }; -class pentium3_device : public pentium_device +class pentium3_device : public pentium_pro_device { public: // construction/destruction @@ -1626,6 +1630,8 @@ public: pentium4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); protected: + virtual uint64_t opcode_rdmsr(bool &valid_msr) override; + virtual void opcode_wrmsr(uint64_t data, bool &valid_msr) override; virtual void device_start() override; virtual void device_reset() override; }; diff --git a/src/devices/cpu/i386/i386priv.h b/src/devices/cpu/i386/i386priv.h index f341edf2551..1e5439f205f 100644 --- a/src/devices/cpu/i386/i386priv.h +++ b/src/devices/cpu/i386/i386priv.h @@ -1200,227 +1200,4 @@ void i386_device::WRITEPORT32(offs_t port, uint32_t value) } } -/*********************************************************************************** - MSR ACCESS -***********************************************************************************/ - -// Pentium MSR handling -uint64_t i386_device::pentium_msr_read(uint32_t offset,uint8_t *valid_msr) -{ - switch(offset) - { - // Machine Check Exception (TODO) - case 0x00: - *valid_msr = 1; - popmessage("RDMSR: Reading P5_MC_ADDR"); - return 0; - case 0x01: - *valid_msr = 1; - popmessage("RDMSR: Reading P5_MC_TYPE"); - return 0; - // Time Stamp Counter - case 0x10: - *valid_msr = 1; - popmessage("RDMSR: Reading TSC"); - return m_tsc; - // Event Counters (TODO) - case 0x11: // CESR - *valid_msr = 1; - popmessage("RDMSR: Reading CESR"); - return 0; - case 0x12: // CTR0 - *valid_msr = 1; - return m_perfctr[0]; - case 0x13: // CTR1 - *valid_msr = 1; - return m_perfctr[1]; - default: - if(!(offset & ~0xf)) // 2-f are test registers - { - *valid_msr = 1; - logerror("RDMSR: Reading test MSR %x", offset); - return 0; - } - logerror("RDMSR: invalid P5 MSR read %08x at %08x\n",offset,m_pc-2); - *valid_msr = 0; - return 0; - } - return -1; -} - -void i386_device::pentium_msr_write(uint32_t offset, uint64_t data, uint8_t *valid_msr) -{ - switch(offset) - { - // Machine Check Exception (TODO) - case 0x00: - popmessage("WRMSR: Writing P5_MC_ADDR"); - *valid_msr = 1; - break; - case 0x01: - popmessage("WRMSR: Writing P5_MC_TYPE"); - *valid_msr = 1; - break; - // Time Stamp Counter - case 0x10: - m_tsc = data; - popmessage("WRMSR: Writing to TSC"); - *valid_msr = 1; - break; - // Event Counters (TODO) - case 0x11: // CESR - popmessage("WRMSR: Writing to CESR"); - *valid_msr = 1; - break; - case 0x12: // CTR0 - m_perfctr[0] = data; - *valid_msr = 1; - break; - case 0x13: // CTR1 - m_perfctr[1] = data; - *valid_msr = 1; - break; - default: - if(!(offset & ~0xf)) // 2-f are test registers - { - *valid_msr = 1; - logerror("WRMSR: Writing test MSR %x", offset); - break; - } - logerror("WRMSR: invalid MSR write %08x (%08x%08x) at %08x\n",offset,(uint32_t)(data >> 32),(uint32_t)data,m_pc-2); - *valid_msr = 0; - break; - } -} - -// P6 (Pentium Pro, Pentium II, Pentium III) MSR handling -uint64_t i386_device::p6_msr_read(uint32_t offset,uint8_t *valid_msr) -{ - switch(offset) - { - // Machine Check Exception (TODO) - case 0x00: - *valid_msr = 1; - popmessage("RDMSR: Reading P5_MC_ADDR"); - return 0; - case 0x01: - *valid_msr = 1; - popmessage("RDMSR: Reading P5_MC_TYPE"); - return 0; - // Time Stamp Counter - case 0x10: - *valid_msr = 1; - popmessage("RDMSR: Reading TSC"); - return m_tsc; - // Performance Counters (TODO) - case 0xc1: // PerfCtr0 - *valid_msr = 1; - return m_perfctr[0]; - case 0xc2: // PerfCtr1 - *valid_msr = 1; - return m_perfctr[1]; - default: - logerror("RDMSR: unimplemented register called %08x at %08x\n",offset,m_pc-2); - *valid_msr = 1; - return 0; - } - return -1; -} - -void i386_device::p6_msr_write(uint32_t offset, uint64_t data, uint8_t *valid_msr) -{ - switch(offset) - { - // Time Stamp Counter - case 0x10: - m_tsc = data; - popmessage("WRMSR: Writing to TSC"); - *valid_msr = 1; - break; - // Performance Counters (TODO) - case 0xc1: // PerfCtr0 - m_perfctr[0] = data; - *valid_msr = 1; - break; - case 0xc2: // PerfCtr1 - m_perfctr[1] = data; - *valid_msr = 1; - break; - default: - logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n",offset,(uint32_t)(data >> 32),(uint32_t)data,m_pc-2); - *valid_msr = 1; - break; - } -} - - -// PIV (Pentium 4+) -uint64_t i386_device::piv_msr_read(uint32_t offset,uint8_t *valid_msr) -{ - switch(offset) - { - default: - logerror("RDMSR: unimplemented register called %08x at %08x\n",offset,m_pc-2); - *valid_msr = 1; - return 0; - } - return -1; -} - -void i386_device::piv_msr_write(uint32_t offset, uint64_t data, uint8_t *valid_msr) -{ - switch(offset) - { - default: - logerror("WRMSR: unimplemented register called %08x (%08x%08x) at %08x\n",offset,(uint32_t)(data >> 32),(uint32_t)data,m_pc-2); - *valid_msr = 1; - break; - } -} - -uint64_t i386_device::MSR_READ(uint32_t offset,uint8_t *valid_msr) -{ - uint64_t res; - uint8_t cpu_type = (m_cpu_version >> 8) & 0x0f; - - *valid_msr = 0; - - switch(cpu_type) - { - case 5: // Pentium - res = pentium_msr_read(offset,valid_msr); - break; - case 6: // Pentium Pro, Pentium II, Pentium III - res = p6_msr_read(offset,valid_msr); - break; - case 15: // Pentium 4+ - res = piv_msr_read(offset,valid_msr); - break; - default: - res = 0; - break; - } - - return res; -} - -void i386_device::MSR_WRITE(uint32_t offset, uint64_t data, uint8_t *valid_msr) -{ - *valid_msr = 0; - uint8_t cpu_type = (m_cpu_version >> 8) & 0x0f; - - switch(cpu_type) - { - case 5: // Pentium - pentium_msr_write(offset,data,valid_msr); - break; - case 6: // Pentium Pro, Pentium II, Pentium III - p6_msr_write(offset,data,valid_msr); - break; - case 15: // Pentium 4+ - piv_msr_write(offset,data,valid_msr); - break; - } -} - #endif /* __I386_H__ */ diff --git a/src/devices/cpu/i386/i486ops.hxx b/src/devices/cpu/i386/i486ops.hxx index bb96ac5411b..37c8ee8d1c2 100644 --- a/src/devices/cpu/i386/i486ops.hxx +++ b/src/devices/cpu/i386/i486ops.hxx @@ -34,7 +34,8 @@ void i386_device::i486_cpuid() // Opcode 0x0F A2 default: { - logerror("CPUID called with unsupported EAX=%08x at %08x!\n", REG32(EAX), m_eip); + // call the model specific implementation + opcode_cpuid(); break; } } diff --git a/src/devices/cpu/i386/pentops.hxx b/src/devices/cpu/i386/pentops.hxx index ee67c5ca050..d5f6f6ca592 100644 --- a/src/devices/cpu/i386/pentops.hxx +++ b/src/devices/cpu/i386/pentops.hxx @@ -56,14 +56,17 @@ void i386_device::WRITEXMM_HI64(uint32_t ea,i386_device::XMM_REG &r) void i386_device::pentium_rdmsr() // Opcode 0x0f 32 { uint64_t data; - uint8_t valid_msr = 0; + bool valid_msr = false; - data = MSR_READ(REG32(ECX),&valid_msr); - REG32(EDX) = data >> 32; - REG32(EAX) = data & 0xffffffff; - - if(m_CPL != 0 || valid_msr == 0) // if current privilege level isn't 0 or the register isn't recognized ... - FAULT(FAULT_GP,0) // ... throw a general exception fault + // call the model specific implementation + data = opcode_rdmsr(valid_msr); + if (m_CPL != 0 || valid_msr == false) // if current privilege level isn't 0 or the register isn't recognized ... + FAULT(FAULT_GP, 0) // ... throw a general exception fault + else + { + REG32(EDX) = data >> 32; + REG32(EAX) = data & 0xffffffff; + } CYCLES(CYCLES_RDMSR); } @@ -71,12 +74,13 @@ void i386_device::pentium_rdmsr() // Opcode 0x0f 32 void i386_device::pentium_wrmsr() // Opcode 0x0f 30 { uint64_t data; - uint8_t valid_msr = 0; + bool valid_msr = false; data = (uint64_t)REG32(EAX); data |= (uint64_t)(REG32(EDX)) << 32; - MSR_WRITE(REG32(ECX),data,&valid_msr); + // call the model specific implementation + opcode_wrmsr(data, valid_msr); if(m_CPL != 0 || valid_msr == 0) // if current privilege level isn't 0 or the register isn't recognized FAULT(FAULT_GP,0) // ... throw a general exception fault -- cgit v1.2.3