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
This commit is contained in:
yz70s 2018-11-02 07:58:38 +01:00
parent 99e50b3d41
commit 95c50fed36
5 changed files with 237 additions and 248 deletions

View File

@ -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<util::disasm_interface> i386_device::create_disassembler()
return std::make_unique<i386_disassembler>(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;
}
}

View File

@ -77,6 +77,12 @@ protected:
virtual std::unique_ptr<util::disasm_interface> 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;
};

View File

@ -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__ */

View File

@ -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;
}
}

View File

@ -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