summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/i386/i386.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/i386/i386.cpp')
-rw-r--r--src/devices/cpu/i386/i386.cpp3738
1 files changed, 956 insertions, 2782 deletions
diff --git a/src/devices/cpu/i386/i386.cpp b/src/devices/cpu/i386/i386.cpp
index 3c68bbf1471..c791e0b36a1 100644
--- a/src/devices/cpu/i386/i386.cpp
+++ b/src/devices/cpu/i386/i386.cpp
@@ -14,7 +14,7 @@
Intel Pentium Pro
Intel Pentium II
Intel Pentium III
- Amd Athlon XP
+ Amd Athlon XP (athlon.cpp)
Intel Pentium 4
*/
@@ -41,7 +41,6 @@ DEFINE_DEVICE_TYPE(MEDIAGX, mediagx_device, "mediagx", "Cyrix MediaG
DEFINE_DEVICE_TYPE(PENTIUM_PRO, pentium_pro_device, "pentium_pro", "Intel Pentium Pro")
DEFINE_DEVICE_TYPE(PENTIUM2, pentium2_device, "pentium2", "Intel Pentium II")
DEFINE_DEVICE_TYPE(PENTIUM3, pentium3_device, "pentium3", "Intel Pentium III")
-DEFINE_DEVICE_TYPE(ATHLONXP, athlonxp_device, "athlonxp", "Amd Athlon XP")
DEFINE_DEVICE_TYPE(PENTIUM4, pentium4_device, "pentium4", "Intel Pentium 4")
@@ -131,15 +130,6 @@ pentium3_device::pentium3_device(const machine_config &mconfig, const char *tag,
set_vtlb_dynamic_entries(96);
}
-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);
-}
-
pentium4_device::pentium4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: pentium_device(mconfig, PENTIUM4, tag, owner, clock)
{
@@ -319,173 +309,1015 @@ bool i386_device::translate_address(int pl, int type, uint32_t *address, uint32_
return true;
}
-uint32_t i386_device::i386_load_protected_mode_segment(I386_SREG *seg, uint64_t *desc )
+/***********************************************************************************/
+
+void i386_device::CHANGE_PC(uint32_t pc)
{
- uint32_t v1,v2;
- uint32_t base, limit;
- int entry;
+ m_pc = i386_translate(CS, pc, -1 );
+}
+
+void i386_device::NEAR_BRANCH(int32_t offs)
+{
+ /* TODO: limit */
+ m_eip += offs;
+ m_pc += offs;
+}
+
+uint8_t i386_device::FETCH()
+{
+ uint8_t value;
+ uint32_t address = m_pc, error;
+
+ if(!translate_address(m_CPL,TRANSLATE_FETCH,&address,&error))
+ PF_THROW(error);
+
+ value = mem_pr8(address & m_a20_mask);
+#ifdef DEBUG_MISSING_OPCODE
+ m_opcode_bytes[m_opcode_bytes_length] = value;
+ m_opcode_bytes_length = (m_opcode_bytes_length + 1) & 15;
+#endif
+ m_eip++;
+ m_pc++;
+ return value;
+}
+uint16_t i386_device::FETCH16()
+{
+ uint16_t value;
+ uint32_t address = m_pc, error;
+
+ if( !WORD_ALIGNED(address) ) { /* Unaligned read */
+ value = (FETCH() << 0);
+ value |= (FETCH() << 8);
+ } else {
+ if(!translate_address(m_CPL,TRANSLATE_FETCH,&address,&error))
+ PF_THROW(error);
+ address &= m_a20_mask;
+ value = mem_pr16(address);
+ m_eip += 2;
+ m_pc += 2;
+ }
+ return value;
+}
+uint32_t i386_device::FETCH32()
+{
+ uint32_t value;
+ uint32_t address = m_pc, error;
+
+ if( !DWORD_ALIGNED(m_pc) ) { /* Unaligned read */
+ value = (FETCH() << 0);
+ value |= (FETCH() << 8);
+ value |= (FETCH() << 16);
+ value |= (FETCH() << 24);
+ } else {
+ if(!translate_address(m_CPL,TRANSLATE_FETCH,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ value = mem_pr32(address);
+ m_eip += 4;
+ m_pc += 4;
+ }
+ return value;
+}
+
+uint8_t i386_device::READ8PL(uint32_t ea, uint8_t privilege)
+{
+ uint32_t address = ea, error;
+
+ if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
+ PF_THROW(error);
- if(!seg->selector)
+ address &= m_a20_mask;
+ return m_program->read_byte(address);
+}
+
+uint16_t i386_device::READ16PL(uint32_t ea, uint8_t privilege)
+{
+ uint16_t value;
+ uint32_t address = ea, error;
+
+ switch (ea & 3)
{
- seg->flags = 0;
- seg->base = 0;
- seg->limit = 0;
- seg->d = 0;
- seg->valid = false;
- return 0;
+ case 0:
+ case 2:
+ if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ value = m_program->read_word(address);
+ break;
+
+ case 1:
+ if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ value = m_program->read_dword(address - 1, 0x00ffff00) >> 8;
+ break;
+
+ case 3:
+ value = READ8PL(ea, privilege);
+ value |= READ8PL(ea + 1, privilege) << 8;
+ break;
}
- if ( seg->selector & 0x4 )
+ return value;
+}
+
+uint32_t i386_device::READ32PL(uint32_t ea, uint8_t privilege)
+{
+ uint32_t value;
+ uint32_t address = ea, error;
+
+ switch (ea & 3)
{
- base = m_ldtr.base;
- limit = m_ldtr.limit;
- } else {
- base = m_gdtr.base;
- limit = m_gdtr.limit;
+ case 0:
+ if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ value = m_program->read_dword(address);
+ break;
+
+ case 1:
+ if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ value = m_program->read_dword(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 |= m_program->read_dword(address, 0x00ffffff) << 8;
+ break;
}
- entry = seg->selector & ~0x7;
- if (limit == 0 || entry + 7 > limit)
- return 0;
+ return value;
+}
- v1 = READ32PL0(base + entry );
- v2 = READ32PL0(base + entry + 4 );
+uint64_t i386_device::READ64PL(uint32_t ea, uint8_t privilege)
+{
+ uint64_t value;
+ uint32_t address = ea, error;
- seg->flags = (v2 >> 8) & 0xf0ff;
- seg->base = (v2 & 0xff000000) | ((v2 & 0xff) << 16) | ((v1 >> 16) & 0xffff);
- seg->limit = (v2 & 0xf0000) | (v1 & 0xffff);
- if (seg->flags & 0x8000)
- seg->limit = (seg->limit << 12) | 0xfff;
- seg->d = (seg->flags & 0x4000) ? 1 : 0;
- seg->valid = true;
+ switch (ea & 3)
+ {
+ case 0:
+ value = READ32PL(ea, privilege);
+ value |= uint64_t(READ32PL(ea + 2, privilege)) << 32;
+ break;
- if(desc)
- *desc = ((uint64_t)v2<<32)|v1;
- return 1;
+ case 1:
+ if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ value = m_program->read_dword(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(m_program->read_dword(address, 0x00ffffff)) << 40;
+ break;
+ }
+
+ return value;
}
-void i386_device::i386_load_call_gate(I386_CALL_GATE *gate)
+uint16_t i386sx_device::READ16PL(uint32_t ea, uint8_t privilege)
{
- uint32_t v1,v2;
- uint32_t base,limit;
- int entry;
+ uint16_t value;
+ uint32_t address = ea, error;
- if ( gate->segment & 0x4 )
+ if (WORD_ALIGNED(ea))
{
- base = m_ldtr.base;
- limit = m_ldtr.limit;
- } else {
- base = m_gdtr.base;
- limit = m_gdtr.limit;
+ if(!translate_address(privilege,TRANSLATE_READ,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ return m_program->read_word(address);
+ }
+ else
+ {
+ /* Unaligned read */
+ value = READ8PL(ea, privilege);
+ value |= READ8PL(ea + 1, privilege) << 8;
+ return value;
}
+}
- entry = gate->segment & ~0x7;
- if (limit == 0 || entry + 7 > limit)
- return;
+uint32_t i386sx_device::READ32PL(uint32_t ea, uint8_t privilege)
+{
+ uint32_t value;
+
+ if (WORD_ALIGNED(ea))
+ {
+ value = READ16PL(ea, privilege);
+ value |= READ16PL(ea + 2, privilege) << 16;
+ return value;
+ }
+ else
+ {
+ value = READ8PL(ea, privilege);
+ value |= READ16PL(ea + 1, privilege) << 8;
+ value |= READ8PL(ea + 3, privilege) << 24;
+ return value;
+ }
+}
- v1 = READ32PL0(base + entry );
- v2 = READ32PL0(base + entry + 4 );
+uint64_t i386sx_device::READ64PL(uint32_t ea, uint8_t privilege)
+{
+ uint64_t value;
- /* Note that for task gates, offset and dword_count are not used */
- gate->selector = (v1 >> 16) & 0xffff;
- gate->offset = (v1 & 0x0000ffff) | (v2 & 0xffff0000);
- gate->ar = (v2 >> 8) & 0xff;
- gate->dword_count = v2 & 0x001f;
- gate->present = (gate->ar >> 7) & 0x01;
- gate->dpl = (gate->ar >> 5) & 0x03;
+ if (WORD_ALIGNED(ea))
+ {
+ value = READ16PL(ea, privilege);
+ value |= uint64_t(READ16PL(ea + 2, privilege)) << 16;
+ value |= uint64_t(READ16PL(ea + 4, privilege)) << 32;
+ value |= uint64_t(READ16PL(ea + 6, privilege)) << 48;
+ return value;
+ }
+ else
+ {
+ value = READ8PL(ea, privilege);
+ value |= uint64_t(READ16PL(ea + 1, privilege)) << 8;
+ value |= uint64_t(READ16PL(ea + 3, privilege)) << 24;
+ value |= uint64_t(READ16PL(ea + 5, privilege)) << 40;
+ value |= uint64_t(READ8PL(ea + 7, privilege)) << 56;
+ return value;
+ }
}
-void i386_device::i386_set_descriptor_accessed(uint16_t selector)
+void i386_device::WRITE_TEST(uint32_t ea)
{
- // assume the selector is valid, we don't need to check it again
- uint32_t base, addr;
- uint8_t rights;
- if(!(selector & ~3))
- return;
+ uint32_t address = ea, error;
+ if(!translate_address(m_CPL,TRANSLATE_WRITE,&address,&error))
+ PF_THROW(error);
+}
- if ( selector & 0x4 )
- base = m_ldtr.base;
+void i386_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;
+ m_program->write_byte(address, value);
+}
+
+void i386_device::WRITE16PL(uint32_t ea, uint8_t privilege, uint16_t value)
+{
+ uint32_t address = ea, error;
+
+ switch(ea & 3)
+ {
+ case 0:
+ case 2:
+ if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ m_program->write_word(address, value);
+ break;
+
+ case 1:
+ if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ m_program->write_dword(address - 1, value << 8, 0x00ffff00);
+ break;
+
+ case 3:
+ WRITE8PL(ea, privilege, value & 0xff);
+ WRITE8PL(ea + 1, privilege, (value >> 8) & 0xff);
+ break;
+ }
+}
+
+void i386_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;
+ m_program->write_dword(address, value);
+ break;
+
+ case 1:
+ if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ m_program->write_dword(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;
+ m_program->write_dword(address, value >> 8, 0x00ffffff);
+ break;
+ }
+}
+
+void i386_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;
+ m_program->write_dword(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;
+ m_program->write_dword(address, (value >> 40) & 0x00ffffff, 0x00ffffff);
+ break;
+ }
+}
+
+void i386sx_device::WRITE16PL(uint32_t ea, uint8_t privilege, uint16_t value)
+{
+ uint32_t address = ea, error;
+
+ if (WORD_ALIGNED(ea))
+ {
+ if(!translate_address(privilege,TRANSLATE_WRITE,&address,&error))
+ PF_THROW(error);
+
+ address &= m_a20_mask;
+ m_program->write_word(address, value);
+ }
else
- base = m_gdtr.base;
+ {
+ WRITE8PL(ea, privilege, value & 0xff);
+ WRITE8PL(ea + 1, privilege, (value >> 8) & 0xff);
+ }
+}
+
+void i386sx_device::WRITE32PL(uint32_t ea, uint8_t privilege, uint32_t value)
+{
+ if (WORD_ALIGNED(ea))
+ {
+ WRITE16PL(ea, privilege, value & 0xffff);
+ WRITE16PL(ea + 2, privilege, (value >> 16) & 0xffff);
+ }
+ else
+ {
+ WRITE8PL(ea, privilege, value & 0xff);
+ WRITE16PL(ea + 1, privilege, (value >> 8) & 0xffff);
+ WRITE8PL(ea + 3, privilege, (value >> 24) & 0xff);
+ }
+}
+
+void i386sx_device::WRITE64PL(uint32_t ea, uint8_t privilege, uint64_t value)
+{
+ if (WORD_ALIGNED(ea))
+ {
+ WRITE16PL(ea, privilege, value & 0xffff);
+ WRITE16PL(ea + 2, privilege, (value >> 16) & 0xffff);
+ WRITE16PL(ea + 4, privilege, (value >> 32) & 0xffff);
+ WRITE16PL(ea + 6, privilege, (value >> 48) & 0xffff);
+ }
+ else
+ {
+ WRITE8PL(ea, privilege, value & 0xff);
+ WRITE16PL(ea + 1, privilege, (value >> 8) & 0xffff);
+ WRITE16PL(ea + 3, privilege, (value >> 24) & 0xffff);
+ WRITE16PL(ea + 5, privilege, (value >> 40) & 0xffff);
+ WRITE8PL(ea + 7, privilege, (value >> 56) & 0xff);
+ }
+}
+
+/***********************************************************************************/
+
+uint8_t i386_device::OR8(uint8_t dst, uint8_t src)
+{
+ uint8_t res = dst | src;
+ m_CF = m_OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+uint16_t i386_device::OR16(uint16_t dst, uint16_t src)
+{
+ uint16_t res = dst | src;
+ m_CF = m_OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+uint32_t i386_device::OR32(uint32_t dst, uint32_t src)
+{
+ uint32_t res = dst | src;
+ m_CF = m_OF = 0;
+ SetSZPF32(res);
+ return res;
+}
- addr = base + (selector & ~7) + 5;
- i386_translate_address(TRANSLATE_READ, &addr, nullptr);
- rights = m_program->read_byte(addr);
- // Should a fault be thrown if the table is read only?
- m_program->write_byte(addr, rights | 1);
+uint8_t i386_device::AND8(uint8_t dst, uint8_t src)
+{
+ uint8_t res = dst & src;
+ m_CF = m_OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+uint16_t i386_device::AND16(uint16_t dst, uint16_t src)
+{
+ uint16_t res = dst & src;
+ m_CF = m_OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+uint32_t i386_device::AND32(uint32_t dst, uint32_t src)
+{
+ uint32_t res = dst & src;
+ m_CF = m_OF = 0;
+ SetSZPF32(res);
+ return res;
+}
+
+uint8_t i386_device::XOR8(uint8_t dst, uint8_t src)
+{
+ uint8_t res = dst ^ src;
+ m_CF = m_OF = 0;
+ SetSZPF8(res);
+ return res;
+}
+uint16_t i386_device::XOR16(uint16_t dst, uint16_t src)
+{
+ uint16_t res = dst ^ src;
+ m_CF = m_OF = 0;
+ SetSZPF16(res);
+ return res;
+}
+uint32_t i386_device::XOR32(uint32_t dst, uint32_t src)
+{
+ uint32_t res = dst ^ src;
+ m_CF = m_OF = 0;
+ SetSZPF32(res);
+ return res;
+}
+
+#define SUB8(dst, src) SBB8(dst, src, 0)
+uint8_t i386_device::SBB8(uint8_t dst, uint8_t src, uint8_t b)
+{
+ uint16_t res = (uint16_t)dst - (uint16_t)src - (uint8_t)b;
+ SetCF8(res);
+ SetOF_Sub8(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF8(res);
+ return (uint8_t)res;
}
-void i386_device::i386_load_segment_descriptor(int segment )
+#define SUB16(dst, src) SBB16(dst, src, 0)
+uint16_t i386_device::SBB16(uint16_t dst, uint16_t src, uint16_t b)
+{
+ uint32_t res = (uint32_t)dst - (uint32_t)src - (uint32_t)b;
+ SetCF16(res);
+ SetOF_Sub16(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF16(res);
+ return (uint16_t)res;
+}
+
+#define SUB32(dst, src) SBB32(dst, src, 0)
+uint32_t i386_device::SBB32(uint32_t dst, uint32_t src, uint32_t b)
+{
+ uint64_t res = (uint64_t)dst - (uint64_t)src - (uint64_t) b;
+ SetCF32(res);
+ SetOF_Sub32(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF32(res);
+ return (uint32_t)res;
+}
+
+#define ADD8(dst, src) ADC8(dst, src, 0)
+uint8_t i386_device::ADC8(uint8_t dst, uint8_t src, uint8_t c)
+{
+ uint16_t res = (uint16_t)dst + (uint16_t)src + (uint16_t)c;
+ SetCF8(res);
+ SetOF_Add8(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF8(res);
+ return (uint8_t)res;
+}
+
+#define ADD16(dst, src) ADC16(dst, src, 0)
+uint16_t i386_device::ADC16(uint16_t dst, uint16_t src, uint8_t c)
+{
+ uint32_t res = (uint32_t)dst + (uint32_t)src + (uint32_t)c;
+ SetCF16(res);
+ SetOF_Add16(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF16(res);
+ return (uint16_t)res;
+}
+
+#define ADD32(dst, src) ADC32(dst, src, 0)
+uint32_t i386_device::ADC32(uint32_t dst, uint32_t src, uint32_t c)
+{
+ uint64_t res = (uint64_t)dst + (uint64_t)src + (uint64_t) c;
+ SetCF32(res);
+ SetOF_Add32(res,src,dst);
+ SetAF(res,src,dst);
+ SetSZPF32(res);
+ return (uint32_t)res;
+}
+
+uint8_t i386_device::INC8(uint8_t dst)
+{
+ uint16_t res = (uint16_t)dst + 1;
+ SetOF_Add8(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF8(res);
+ return (uint8_t)res;
+}
+uint16_t i386_device::INC16(uint16_t dst)
+{
+ uint32_t res = (uint32_t)dst + 1;
+ SetOF_Add16(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF16(res);
+ return (uint16_t)res;
+}
+uint32_t i386_device::INC32(uint32_t dst)
+{
+ uint64_t res = (uint64_t)dst + 1;
+ SetOF_Add32(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF32(res);
+ return (uint32_t)res;
+}
+
+uint8_t i386_device::DEC8(uint8_t dst)
+{
+ uint16_t res = (uint16_t)dst - 1;
+ SetOF_Sub8(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF8(res);
+ return (uint8_t)res;
+}
+uint16_t i386_device::DEC16(uint16_t dst)
+{
+ uint32_t res = (uint32_t)dst - 1;
+ SetOF_Sub16(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF16(res);
+ return (uint16_t)res;
+}
+uint32_t i386_device::DEC32(uint32_t dst)
+{
+ uint64_t res = (uint64_t)dst - 1;
+ SetOF_Sub32(res,1,dst);
+ SetAF(res,1,dst);
+ SetSZPF32(res);
+ return (uint32_t)res;
+}
+
+
+
+void i386_device::PUSH16(uint16_t value)
+{
+ uint32_t ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) - 2;
+ ea = i386_translate(SS, new_esp, 1);
+ WRITE16(ea, value );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = (REG16(SP) - 2) & 0xffff;
+ ea = i386_translate(SS, new_esp, 1);
+ WRITE16(ea, value );
+ REG16(SP) = new_esp;
+ }
+}
+void i386_device::PUSH32(uint32_t value)
+{
+ uint32_t ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) - 4;
+ ea = i386_translate(SS, new_esp, 1);
+ WRITE32(ea, value );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = (REG16(SP) - 4) & 0xffff;
+ ea = i386_translate(SS, new_esp, 1);
+ WRITE32(ea, value );
+ REG16(SP) = new_esp;
+ }
+}
+
+void i386_device::PUSH32SEG(uint32_t value)
+{
+ uint32_t ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) - 4;
+ ea = i386_translate(SS, new_esp, 1);
+ ((m_cpu_version & 0xf00) == 0x300) ? WRITE16(ea, value) : WRITE32(ea, value ); // 486 also?
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = (REG16(SP) - 4) & 0xffff;
+ ea = i386_translate(SS, new_esp, 1);
+ ((m_cpu_version & 0xf00) == 0x300) ? WRITE16(ea, value) : WRITE32(ea, value );
+ REG16(SP) = new_esp;
+ }
+}
+
+void i386_device::PUSH8(uint8_t value)
+{
+ if( m_operand_size ) {
+ PUSH32((int32_t)(int8_t)value);
+ } else {
+ PUSH16((int16_t)(int8_t)value);
+ }
+}
+
+uint8_t i386_device::POP8()
+{
+ uint8_t value;
+ uint32_t ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) + 1;
+ ea = i386_translate(SS, new_esp - 1, 0);
+ value = READ8(ea );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = REG16(SP) + 1;
+ ea = i386_translate(SS, (new_esp - 1) & 0xffff, 0);
+ value = READ8(ea );
+ REG16(SP) = new_esp;
+ }
+ return value;
+}
+uint16_t i386_device::POP16()
+{
+ uint16_t value;
+ uint32_t ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) + 2;
+ ea = i386_translate(SS, new_esp - 2, 0);
+ value = READ16(ea );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = REG16(SP) + 2;
+ ea = i386_translate(SS, (new_esp - 2) & 0xffff, 0);
+ value = READ16(ea );
+ REG16(SP) = new_esp;
+ }
+ return value;
+}
+uint32_t i386_device::POP32()
+{
+ uint32_t value;
+ uint32_t ea, new_esp;
+ if( STACK_32BIT ) {
+ new_esp = REG32(ESP) + 4;
+ ea = i386_translate(SS, new_esp - 4, 0);
+ value = READ32(ea );
+ REG32(ESP) = new_esp;
+ } else {
+ new_esp = REG16(SP) + 4;
+ ea = i386_translate(SS, (new_esp - 4) & 0xffff, 0);
+ value = READ32(ea );
+ REG16(SP) = new_esp;
+ }
+ return value;
+}
+
+void i386_device::BUMP_SI(int adjustment)
+{
+ if ( m_address_size )
+ REG32(ESI) += ((m_DF) ? -adjustment : +adjustment);
+ else
+ REG16(SI) += ((m_DF) ? -adjustment : +adjustment);
+}
+
+void i386_device::BUMP_DI(int adjustment)
+{
+ if ( m_address_size )
+ REG32(EDI) += ((m_DF) ? -adjustment : +adjustment);
+ else
+ REG16(DI) += ((m_DF) ? -adjustment : +adjustment);
+}
+
+void i386_device::CYCLES(int x)
{
if (PROTECTED_MODE)
{
- uint16_t old_flags = m_sreg[segment].flags;
- if (!V8086_MODE)
+ m_cycles -= m_cycle_table_pm[x];
+ }
+ else
+ {
+ m_cycles -= m_cycle_table_rm[x];
+ }
+}
+
+void i386_device::CYCLES_RM(int modrm, int r, int m)
+{
+ if (modrm >= 0xc0)
+ {
+ if (PROTECTED_MODE)
{
- i386_load_protected_mode_segment(&m_sreg[segment], nullptr);
- if (m_sreg[segment].selector)
- {
- i386_set_descriptor_accessed(m_sreg[segment].selector);
- m_sreg[segment].flags |= 0x0001;
- }
+ m_cycles -= m_cycle_table_pm[r];
}
else
{
- m_sreg[segment].base = m_sreg[segment].selector << 4;
- m_sreg[segment].limit = 0xffff;
- m_sreg[segment].flags = (segment == CS) ? 0x00fb : 0x00f3;
- m_sreg[segment].d = 0;
- m_sreg[segment].valid = true;
+ m_cycles -= m_cycle_table_rm[r];
}
- if (segment == CS && m_sreg[segment].flags != old_flags)
- debugger_privilege_hook();
}
else
{
- m_sreg[segment].base = m_sreg[segment].selector << 4;
- m_sreg[segment].d = 0;
- m_sreg[segment].valid = true;
-
- if (segment == CS)
+ if (PROTECTED_MODE)
+ {
+ m_cycles -= m_cycle_table_pm[m];
+ }
+ else
{
- if (!m_performed_intersegment_jump)
- m_sreg[segment].base |= 0xfff00000;
- if (m_cpu_version < 0x500)
- m_sreg[segment].flags = 0x93;
+ m_cycles -= m_cycle_table_rm[m];
}
}
}
-/* Retrieves the stack selector located in the current TSS */
-uint32_t i386_device::i386_get_stack_segment(uint8_t privilege)
+/**********************************************************************************/
+
+void i386_device::check_ioperm(offs_t port, uint8_t mask)
{
- uint32_t ret;
- if(privilege >= 3)
- return 0;
+ uint8_t IOPL, map;
+ uint16_t IOPB;
+ uint32_t address;
- if(m_task.flags & 8)
- ret = READ32PL0((m_task.base+8) + (8*privilege));
- else
- ret = READ16PL0((m_task.base+4) + (4*privilege));
+ if(!PROTECTED_MODE)
+ return;
- return ret;
+ IOPL = m_IOP1 | (m_IOP2 << 1);
+ if(!V8086_MODE && (m_CPL <= IOPL))
+ return;
+
+ if((m_task.limit < 0x67) || ((m_task.flags & 0xd) != 9))
+ FAULT_THROW(FAULT_GP,0);
+
+ address = m_task.base;
+ IOPB = READ16PL(address+0x66,0);
+ if((IOPB+(port/8)) > m_task.limit)
+ FAULT_THROW(FAULT_GP,0);
+
+ map = READ8PL(address+IOPB+(port/8),0);
+ map >>= (port%8);
+ if(map & mask)
+ FAULT_THROW(FAULT_GP,0);
}
-/* Retrieves the stack pointer located in the current TSS */
-uint32_t i386_device::i386_get_stack_ptr(uint8_t privilege)
+uint8_t i386_device::READPORT8(offs_t port)
{
- uint32_t ret;
- if(privilege >= 3)
- return 0;
+ check_ioperm(port, 1);
+ return m_io->read_byte(port);
+}
+
+void i386_device::WRITEPORT8(offs_t port, uint8_t value)
+{
+ check_ioperm(port, 1);
+ m_io->write_byte(port, value);
+}
+
+uint16_t i386_device::READPORT16(offs_t port)
+{
+ uint16_t value;
+
+ switch (port & 3)
+ {
+ case 0:
+ case 2:
+ check_ioperm(port, 3);
+ value = m_io->read_word(port);
+ break;
+
+ case 1:
+ check_ioperm(port, 3);
+ value = m_io->read_dword(port - 1, 0x00ffff00) >> 8;
+ break;
+
+ case 3:
+ value = READPORT8(port);
+ value |= (READPORT8(port + 1) << 8);
+ break;
+ }
+
+ return value;
+}
+
+void i386_device::WRITEPORT16(offs_t port, uint16_t value)
+{
+ switch (port & 3)
+ {
+ case 0:
+ case 2:
+ check_ioperm(port, 3);
+ m_io->write_word(port, value);
+ break;
+
+ case 1:
+ check_ioperm(port, 3);
+ m_io->write_dword(port - 1, value << 8, 0x00ffff00);
+ break;
+
+ case 3:
+ WRITEPORT8(port, value & 0xff);
+ WRITEPORT8(port + 1, (value >> 8) & 0xff);
+ break;
+ }
+}
+
+uint32_t i386_device::READPORT32(offs_t port)
+{
+ uint32_t value;
+
+ switch (port & 3)
+ {
+ case 0:
+ check_ioperm(port, 0xf);
+ value = m_io->read_dword(port);
+ break;
+
+ case 1:
+ check_ioperm(port, 7);
+ value = m_io->read_dword(port - 1, 0xffffff00) >> 8;
+ value |= READPORT8(port + 3) << 24;
+ break;
+
+ case 2:
+ value = READPORT16(port);
+ value |= READPORT16(port + 2) << 16;
+ break;
+
+ case 3:
+ value = READPORT8(port);
+ check_ioperm(port + 1, 7);
+ value |= m_io->read_dword(port + 1, 0x00ffffff) << 8;
+ break;
+ }
+
+ return value;
+}
+
+void i386_device::WRITEPORT32(offs_t port, uint32_t value)
+{
+ switch (port & 3)
+ {
+ case 0:
+ check_ioperm(port, 0xf);
+ m_io->write_dword(port, value);
+ break;
- if(m_task.flags & 8)
- ret = READ32PL0((m_task.base+4) + (8*privilege));
+ case 1:
+ check_ioperm(port, 7);
+ m_io->write_dword(port - 1, value << 8, 0xffffff00);
+ WRITEPORT8(port + 3, (value >> 24) & 0xff);
+ break;
+
+ case 2:
+ WRITEPORT16(port, value & 0xffff);
+ WRITEPORT16(port + 2, (value >> 16) & 0xffff);
+ break;
+
+ case 3:
+ WRITEPORT8(port, value & 0xff);
+ check_ioperm(port + 1, 7);
+ m_io->write_dword(port + 1, value >> 8, 0x00ffffff);
+ break;
+ }
+}
+
+uint16_t i386sx_device::READPORT16(offs_t port)
+{
+ if (port & 1)
+ {
+ uint16_t value = READPORT8(port);
+ value |= (READPORT8(port + 1) << 8);
+ return value;
+ }
+ else
+ {
+ check_ioperm(port, 3);
+ return m_io->read_word(port);
+ }
+}
+
+void i386sx_device::WRITEPORT16(offs_t port, uint16_t value)
+{
+ if (port & 1)
+ {
+ WRITEPORT8(port, value & 0xff);
+ WRITEPORT8(port + 1, (value >> 8) & 0xff);
+ }
else
- ret = READ16PL0((m_task.base+2) + (4*privilege));
+ {
+ check_ioperm(port, 3);
+ m_io->write_word(port, value);
+ }
+}
- return ret;
+uint32_t i386sx_device::READPORT32(offs_t port)
+{
+ if (port & 1)
+ {
+ uint32_t value = READPORT8(port);
+ value |= (READPORT16(port + 1) << 8);
+ value |= (READPORT8(port + 3) << 24);
+ return value;
+ }
+ else
+ {
+ uint16_t value = READPORT16(port);
+ value |= (READPORT16(port + 2) << 16);
+ return value;
+ }
+}
+
+void i386sx_device::WRITEPORT32(offs_t port, uint32_t value)
+{
+ if (port & 1)
+ {
+ WRITEPORT8(port, value & 0xff);
+ WRITEPORT16(port + 1, (value >> 8) & 0xffff);
+ WRITEPORT8(port + 3, (value >> 24) & 0xff);
+ }
+ else
+ {
+ WRITEPORT16(port, value & 0xffff);
+ WRITEPORT16((port + 2), (value >> 16) & 0xffff);
+ }
}
+/***********************************************************************************/
+
uint32_t i386_device::get_flags() const
{
uint32_t f = 0x2;
@@ -680,864 +1512,6 @@ uint32_t i386_device::GetEA(uint8_t modrm, int rwn)
return i386_translate(segment, ea, rwn );
}
-/* Check segment register for validity when changing privilege level after an RETF */
-void i386_device::i386_check_sreg_validity(int reg)
-{
- uint16_t selector = m_sreg[reg].selector;
- uint8_t CPL = m_CPL;
- uint8_t DPL,RPL;
- I386_SREG desc;
- int invalid;
-
- memset(&desc, 0, sizeof(desc));
- desc.selector = selector;
- i386_load_protected_mode_segment(&desc,nullptr);
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- RPL = selector & 0x03;
-
- /* Must be within the relevant descriptor table limits */
- if(selector & 0x04)
- {
- if((selector & ~0x07) > m_ldtr.limit)
- invalid = 1;
- }
- else
- {
- if((selector & ~0x07) > m_gdtr.limit)
- invalid = 1;
- }
-
- /* Must be either a data or readable code segment */
- if(((desc.flags & 0x0018) == 0x0018 && (desc.flags & 0x0002)) || (desc.flags & 0x0018) == 0x0010)
- invalid = 0;
- else
- invalid = 1;
-
- /* If a data segment or non-conforming code segment, then either DPL >= CPL or DPL >= RPL */
- if(((desc.flags & 0x0018) == 0x0018 && (desc.flags & 0x0004) == 0) || (desc.flags & 0x0018) == 0x0010)
- {
- if((DPL < CPL) || (DPL < RPL))
- invalid = 1;
- }
-
- /* if segment is invalid, then segment register is nulled */
- if(invalid != 0)
- {
- m_sreg[reg].selector = 0;
- i386_load_segment_descriptor(reg);
- }
-}
-
-int i386_device::i386_limit_check(int seg, uint32_t offset)
-{
- if(PROTECTED_MODE && !V8086_MODE)
- {
- if((m_sreg[seg].flags & 0x0018) == 0x0010 && m_sreg[seg].flags & 0x0004) // if expand-down data segment
- {
- // compare if greater then 0xffffffff when we're passed the access size
- if((offset <= m_sreg[seg].limit) || ((m_sreg[seg].d)?0:(offset > 0xffff)))
- {
- logerror("Limit check at 0x%08x failed. Segment %04x, limit %08x, offset %08x (expand-down)\n",m_pc,m_sreg[seg].selector,m_sreg[seg].limit,offset);
- return 1;
- }
- }
- else
- {
- if(offset > m_sreg[seg].limit)
- {
- logerror("Limit check at 0x%08x failed. Segment %04x, limit %08x, offset %08x\n",m_pc,m_sreg[seg].selector,m_sreg[seg].limit,offset);
- return 1;
- }
- }
- }
- return 0;
-}
-
-void i386_device::i386_sreg_load(uint16_t selector, uint8_t reg, bool *fault)
-{
- // Checks done when MOV changes a segment register in protected mode
- uint8_t CPL,RPL,DPL;
-
- CPL = m_CPL;
- RPL = selector & 0x0003;
-
- if(!PROTECTED_MODE || V8086_MODE)
- {
- m_sreg[reg].selector = selector;
- i386_load_segment_descriptor(reg);
- if(fault) *fault = false;
- return;
- }
-
- if(fault) *fault = true;
- if(reg == SS)
- {
- I386_SREG stack;
-
- memset(&stack, 0, sizeof(stack));
- stack.selector = selector;
- i386_load_protected_mode_segment(&stack,nullptr);
- DPL = (stack.flags >> 5) & 0x03;
-
- if((selector & ~0x0003) == 0)
- {
- logerror("SReg Load (%08x): Selector is null.\n",m_pc);
- FAULT(FAULT_GP,0)
- }
- if(selector & 0x0004) // LDT
- {
- if((selector & ~0x0007) > m_ldtr.limit)
- {
- logerror("SReg Load (%08x): Selector is out of LDT bounds.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- }
- else // GDT
- {
- if((selector & ~0x0007) > m_gdtr.limit)
- {
- logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- }
- if (RPL != CPL)
- {
- logerror("SReg Load (%08x): Selector RPL does not equal CPL.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0)
- {
- logerror("SReg Load (%08x): Segment is not a writable data segment.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- if(DPL != CPL)
- {
- logerror("SReg Load (%08x): Segment DPL does not equal CPL.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- if(!(stack.flags & 0x0080))
- {
- logerror("SReg Load (%08x): Segment is not present.\n",m_pc);
- FAULT(FAULT_SS,selector & ~0x03)
- }
- }
- if(reg == DS || reg == ES || reg == FS || reg == GS)
- {
- I386_SREG desc;
-
- if((selector & ~0x0003) == 0)
- {
- m_sreg[reg].selector = selector;
- i386_load_segment_descriptor(reg );
- if(fault) *fault = false;
- return;
- }
-
- memset(&desc, 0, sizeof(desc));
- desc.selector = selector;
- i386_load_protected_mode_segment(&desc,nullptr);
- DPL = (desc.flags >> 5) & 0x03;
-
- if(selector & 0x0004) // LDT
- {
- if((selector & ~0x0007) > m_ldtr.limit)
- {
- logerror("SReg Load (%08x): Selector is out of LDT bounds.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- }
- else // GDT
- {
- if((selector & ~0x0007) > m_gdtr.limit)
- {
- logerror("SReg Load (%08x): Selector is out of GDT bounds.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- }
- if((desc.flags & 0x0018) != 0x10)
- {
- if((((desc.flags & 0x0002) != 0) && ((desc.flags & 0x0018) != 0x18)) || !(desc.flags & 0x10))
- {
- logerror("SReg Load (%08x): Segment is not a data segment or readable code segment.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- }
- if(((desc.flags & 0x0018) == 0x10) || ((!(desc.flags & 0x0004)) && ((desc.flags & 0x0018) == 0x18)))
- {
- // if data or non-conforming code segment
- if((RPL > DPL) || (CPL > DPL))
- {
- logerror("SReg Load (%08x): Selector RPL or CPL is not less or equal to segment DPL.\n",m_pc);
- FAULT(FAULT_GP,selector & ~0x03)
- }
- }
- if(!(desc.flags & 0x0080))
- {
- logerror("SReg Load (%08x): Segment is not present.\n",m_pc);
- FAULT(FAULT_NP,selector & ~0x03)
- }
- }
-
- m_sreg[reg].selector = selector;
- i386_load_segment_descriptor(reg );
- if(fault) *fault = false;
-}
-
-void i386_device::i386_trap(int irq, int irq_gate, int trap_level)
-{
- /* I386 Interrupts/Traps/Faults:
- *
- * 0x00 Divide by zero
- * 0x01 Debug exception
- * 0x02 NMI
- * 0x03 Int3
- * 0x04 Overflow
- * 0x05 Array bounds check
- * 0x06 Illegal Opcode
- * 0x07 FPU not available
- * 0x08 Double fault
- * 0x09 Coprocessor segment overrun
- * 0x0a Invalid task state
- * 0x0b Segment not present
- * 0x0c Stack exception
- * 0x0d General Protection Fault
- * 0x0e Page fault
- * 0x0f Reserved
- * 0x10 Coprocessor error
- */
- uint32_t v1, v2;
- uint32_t offset, oldflags = get_flags();
- uint16_t segment;
- int entry = irq * (PROTECTED_MODE ? 8 : 4);
- int SetRPL;
- m_lock = false;
-
- if( !(PROTECTED_MODE) )
- {
- /* 16-bit */
- PUSH16(oldflags & 0xffff );
- PUSH16(m_sreg[CS].selector );
- if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
- PUSH16(m_eip );
- else
- PUSH16(m_prev_eip );
-
- m_sreg[CS].selector = READ16(m_idtr.base + entry + 2 );
- m_eip = READ16(m_idtr.base + entry );
-
- m_TF = 0;
- m_IF = 0;
- }
- else
- {
- int type;
- uint16_t flags;
- I386_SREG desc;
- uint8_t CPL = m_CPL, DPL; //, RPL = 0;
-
- /* 32-bit */
- v1 = READ32PL0(m_idtr.base + entry );
- v2 = READ32PL0(m_idtr.base + entry + 4 );
- offset = (v2 & 0xffff0000) | (v1 & 0xffff);
- segment = (v1 >> 16) & 0xffff;
- type = (v2>>8) & 0x1F;
- flags = (v2>>8) & 0xf0ff;
-
- if(trap_level == 2)
- {
- logerror("IRQ: Double fault.\n");
- FAULT_EXP(FAULT_DF,0);
- }
- if(trap_level >= 3)
- {
- logerror("IRQ: Triple fault. CPU reset.\n");
- pulse_input_line(INPUT_LINE_RESET, attotime::zero);
- return;
- }
-
- /* segment privilege checks */
- if(entry >= m_idtr.limit)
- {
- logerror("IRQ (%08x): Vector %02xh is past IDT limit.\n",m_pc,entry);
- FAULT_EXP(FAULT_GP,entry+2)
- }
- /* segment must be interrupt gate, trap gate, or task gate */
- if(type != 0x05 && type != 0x06 && type != 0x07 && type != 0x0e && type != 0x0f)
- {
- logerror("IRQ#%02x (%08x): Vector segment %04x is not an interrupt, trap or task gate.\n",irq,m_pc,segment);
- FAULT_EXP(FAULT_GP,entry+2)
- }
-
- if(m_ext == 0) // if software interrupt (caused by INT/INTO/INT3)
- {
- if(((flags >> 5) & 0x03) < CPL)
- {
- logerror("IRQ (%08x): Software IRQ - gate DPL is less than CPL.\n",m_pc);
- FAULT_EXP(FAULT_GP,entry+2)
- }
- if(V8086_MODE)
- {
- if((!m_IOP1 || !m_IOP2) && (m_opcode != 0xcc))
- {
- logerror("IRQ (%08x): Is in Virtual 8086 mode and IOPL != 3.\n",m_pc);
- FAULT(FAULT_GP,0)
- }
-
- }
- }
-
- if((flags & 0x0080) == 0)
- {
- logerror("IRQ: Vector segment is not present.\n");
- FAULT_EXP(FAULT_NP,entry+2)
- }
-
- if(type == 0x05)
- {
- /* Task gate */
- memset(&desc, 0, sizeof(desc));
- desc.selector = segment;
- i386_load_protected_mode_segment(&desc,nullptr);
- if(segment & 0x04)
- {
- logerror("IRQ: Task gate: TSS is not in the GDT.\n");
- FAULT_EXP(FAULT_TS,segment & ~0x03);
- }
- else
- {
- if(segment > m_gdtr.limit)
- {
- logerror("IRQ: Task gate: TSS is past GDT limit.\n");
- FAULT_EXP(FAULT_TS,segment & ~0x03);
- }
- }
- if((desc.flags & 0x000f) != 0x09 && (desc.flags & 0x000f) != 0x01)
- {
- logerror("IRQ: Task gate: TSS is not an available TSS.\n");
- FAULT_EXP(FAULT_TS,segment & ~0x03);
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("IRQ: Task gate: TSS is not present.\n");
- FAULT_EXP(FAULT_NP,segment & ~0x03);
- }
- if(!(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1))
- m_eip = m_prev_eip;
- if(desc.flags & 0x08)
- i386_task_switch(desc.selector,1);
- else
- i286_task_switch(desc.selector,1);
- return;
- }
- else
- {
- /* Interrupt or Trap gate */
- memset(&desc, 0, sizeof(desc));
- desc.selector = segment;
- i386_load_protected_mode_segment(&desc,nullptr);
- CPL = m_CPL; // current privilege level
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
-// RPL = segment & 0x03; // requested privilege level
-
- if((segment & ~0x03) == 0)
- {
- logerror("IRQ: Gate segment is null.\n");
- FAULT_EXP(FAULT_GP,m_ext)
- }
- if(segment & 0x04)
- {
- if((segment & ~0x07) > m_ldtr.limit)
- {
- logerror("IRQ: Gate segment is past LDT limit.\n");
- FAULT_EXP(FAULT_GP,(segment & 0x03)+m_ext)
- }
- }
- else
- {
- if((segment & ~0x07) > m_gdtr.limit)
- {
- logerror("IRQ: Gate segment is past GDT limit.\n");
- FAULT_EXP(FAULT_GP,(segment & 0x03)+m_ext)
- }
- }
- if((desc.flags & 0x0018) != 0x18)
- {
- logerror("IRQ: Gate descriptor is not a code segment.\n");
- FAULT_EXP(FAULT_GP,(segment & 0x03)+m_ext)
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("IRQ: Gate segment is not present.\n");
- FAULT_EXP(FAULT_NP,(segment & 0x03)+m_ext)
- }
- if((desc.flags & 0x0004) == 0 && (DPL < CPL))
- {
- /* IRQ to inner privilege */
- I386_SREG stack;
- uint32_t newESP,oldSS,oldESP;
-
- if(V8086_MODE && DPL)
- {
- logerror("IRQ: Gate to CPL>0 from VM86 mode.\n");
- FAULT_EXP(FAULT_GP,segment & ~0x03);
- }
- /* Check new stack segment in TSS */
- memset(&stack, 0, sizeof(stack));
- stack.selector = i386_get_stack_segment(DPL);
- i386_load_protected_mode_segment(&stack,nullptr);
- oldSS = m_sreg[SS].selector;
- if(flags & 0x0008)
- oldESP = REG32(ESP);
- else
- oldESP = REG16(SP);
- if((stack.selector & ~0x03) == 0)
- {
- logerror("IRQ: New stack selector is null.\n");
- FAULT_EXP(FAULT_GP,m_ext)
- }
- if(stack.selector & 0x04)
- {
- if((stack.selector & ~0x07) > m_ldtr.base)
- {
- logerror("IRQ: New stack selector is past LDT limit.\n");
- FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext)
- }
- }
- else
- {
- if((stack.selector & ~0x07) > m_gdtr.base)
- {
- logerror("IRQ: New stack selector is past GDT limit.\n");
- FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext)
- }
- }
- if((stack.selector & 0x03) != DPL)
- {
- logerror("IRQ: New stack selector RPL is not equal to code segment DPL.\n");
- FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext)
- }
- if(((stack.flags >> 5) & 0x03) != DPL)
- {
- logerror("IRQ: New stack segment DPL is not equal to code segment DPL.\n");
- FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext)
- }
- if(((stack.flags & 0x0018) != 0x10) && (stack.flags & 0x0002) != 0)
- {
- logerror("IRQ: New stack segment is not a writable data segment.\n");
- FAULT_EXP(FAULT_TS,(stack.selector & ~0x03)+m_ext) // #TS(stack selector + EXT)
- }
- if((stack.flags & 0x0080) == 0)
- {
- logerror("IRQ: New stack segment is not present.\n");
- FAULT_EXP(FAULT_SS,(stack.selector & ~0x03)+m_ext) // #TS(stack selector + EXT)
- }
- newESP = i386_get_stack_ptr(DPL);
- if(type & 0x08) // 32-bit gate
- {
- if(((newESP < (V8086_MODE?36:20)) && !(stack.flags & 0x4)) || ((~stack.limit < (~(newESP - 1) + (V8086_MODE?36:20))) && (stack.flags & 0x4)))
- {
- logerror("IRQ: New stack has no space for return addresses.\n");
- FAULT_EXP(FAULT_SS,0)
- }
- }
- else // 16-bit gate
- {
- newESP &= 0xffff;
- if(((newESP < (V8086_MODE?18:10)) && !(stack.flags & 0x4)) || ((~stack.limit < (~(newESP - 1) + (V8086_MODE?18:10))) && (stack.flags & 0x4)))
- {
- logerror("IRQ: New stack has no space for return addresses.\n");
- FAULT_EXP(FAULT_SS,0)
- }
- }
- if(offset > desc.limit)
- {
- logerror("IRQ: New EIP is past code segment limit.\n");
- FAULT_EXP(FAULT_GP,0)
- }
- /* change CPL before accessing the stack */
- m_CPL = DPL;
- /* check for page fault at new stack TODO: check if stack frame crosses page boundary */
- WRITE_TEST(stack.base+newESP-1);
- /* Load new stack segment descriptor */
- m_sreg[SS].selector = stack.selector;
- i386_load_protected_mode_segment(&m_sreg[SS],nullptr);
- i386_set_descriptor_accessed(stack.selector);
- REG32(ESP) = newESP;
- if(V8086_MODE)
- {
- //logerror("IRQ (%08x): Interrupt during V8086 task\n",m_pc);
- if(type & 0x08)
- {
- PUSH32SEG(m_sreg[GS].selector & 0xffff);
- PUSH32SEG(m_sreg[FS].selector & 0xffff);
- PUSH32SEG(m_sreg[DS].selector & 0xffff);
- PUSH32SEG(m_sreg[ES].selector & 0xffff);
- }
- else
- {
- PUSH16(m_sreg[GS].selector);
- PUSH16(m_sreg[FS].selector);
- PUSH16(m_sreg[DS].selector);
- PUSH16(m_sreg[ES].selector);
- }
- m_sreg[GS].selector = 0;
- m_sreg[FS].selector = 0;
- m_sreg[DS].selector = 0;
- m_sreg[ES].selector = 0;
- m_VM = 0;
- i386_load_segment_descriptor(GS);
- i386_load_segment_descriptor(FS);
- i386_load_segment_descriptor(DS);
- i386_load_segment_descriptor(ES);
- }
- if(type & 0x08)
- {
- // 32-bit gate
- PUSH32SEG(oldSS);
- PUSH32(oldESP);
- }
- else
- {
- // 16-bit gate
- PUSH16(oldSS);
- PUSH16(oldESP);
- }
- SetRPL = 1;
- }
- else
- {
- int stack_limit;
- if((desc.flags & 0x0004) || (DPL == CPL))
- {
- /* IRQ to same privilege */
- if(V8086_MODE && !m_ext)
- {
- logerror("IRQ: Gate to same privilege from VM86 mode.\n");
- FAULT_EXP(FAULT_GP,segment & ~0x03);
- }
- if(type == 0x0e || type == 0x0f) // 32-bit gate
- stack_limit = 10;
- else
- stack_limit = 6;
- // TODO: Add check for error code (2 extra bytes)
- if(REG32(ESP) < stack_limit)
- {
- logerror("IRQ: Stack has no space left (needs %i bytes).\n",stack_limit);
- FAULT_EXP(FAULT_SS,0)
- }
- if(offset > desc.limit)
- {
- logerror("IRQ: Gate segment offset is past segment limit.\n");
- FAULT_EXP(FAULT_GP,0)
- }
- SetRPL = 1;
- }
- else
- {
- logerror("IRQ: Gate descriptor is non-conforming, and DPL does not equal CPL.\n");
- FAULT_EXP(FAULT_GP,segment)
- }
- }
- }
- uint32_t tempSP = REG32(ESP);
- try
- {
- // this is ugly but the alternative is worse
- if(type != 0x0e && type != 0x0f) // if not 386 interrupt or trap gate
- {
- PUSH16(oldflags & 0xffff );
- PUSH16(m_sreg[CS].selector );
- if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
- PUSH16(m_eip );
- else
- PUSH16(m_prev_eip );
- }
- else
- {
- PUSH32(oldflags & 0x00ffffff );
- PUSH32SEG(m_sreg[CS].selector );
- if(irq == 3 || irq == 4 || irq == 9 || irq_gate == 1)
- PUSH32(m_eip );
- else
- PUSH32(m_prev_eip );
- }
- }
- catch(uint64_t e)
- {
- REG32(ESP) = tempSP;
- throw e;
- }
- if(SetRPL != 0)
- segment = (segment & ~0x03) | m_CPL;
- m_sreg[CS].selector = segment;
- m_eip = offset;
-
- if(type == 0x0e || type == 0x06)
- m_IF = 0;
- m_TF = 0;
- m_NT = 0;
- }
-
- i386_load_segment_descriptor(CS);
- CHANGE_PC(m_eip);
-
-}
-
-void i386_device::i386_trap_with_error(int irq, int irq_gate, int trap_level, uint32_t error)
-{
- i386_trap(irq,irq_gate,trap_level);
- if(irq == 8 || irq == 10 || irq == 11 || irq == 12 || irq == 13 || irq == 14)
- {
- // for these exceptions, an error code is pushed onto the stack by the processor.
- // no error code is pushed for software interrupts, either.
- if(PROTECTED_MODE)
- {
- uint32_t entry = irq * 8;
- uint32_t v2,type;
- v2 = READ32PL0(m_idtr.base + entry + 4 );
- type = (v2>>8) & 0x1F;
- if(type == 5)
- {
- v2 = READ32PL0(m_idtr.base + entry);
- v2 = READ32PL0(m_gdtr.base + ((v2 >> 16) & 0xfff8) + 4);
- type = (v2>>8) & 0x1F;
- }
- if(type >= 9)
- PUSH32(error);
- else
- PUSH16(error);
- }
- else
- PUSH16(error);
- }
-}
-
-
-void i386_device::i286_task_switch(uint16_t selector, uint8_t nested)
-{
- uint32_t tss;
- I386_SREG seg;
- uint16_t old_task;
- uint8_t ar_byte; // access rights byte
-
- /* TODO: Task State Segment privilege checks */
-
- /* For tasks that aren't nested, clear the busy bit in the task's descriptor */
- if(nested == 0)
- {
- if(m_task.segment & 0x0004)
- {
- ar_byte = READ8(m_ldtr.base + (m_task.segment & ~0x0007) + 5);
- WRITE8(m_ldtr.base + (m_task.segment & ~0x0007) + 5,ar_byte & ~0x02);
- }
- else
- {
- ar_byte = READ8(m_gdtr.base + (m_task.segment & ~0x0007) + 5);
- WRITE8(m_gdtr.base + (m_task.segment & ~0x0007) + 5,ar_byte & ~0x02);
- }
- }
-
- /* Save the state of the current task in the current TSS (TR register base) */
- tss = m_task.base;
- WRITE16(tss+0x0e,m_eip & 0x0000ffff);
- WRITE16(tss+0x10,get_flags() & 0x0000ffff);
- WRITE16(tss+0x12,REG16(AX));
- WRITE16(tss+0x14,REG16(CX));
- WRITE16(tss+0x16,REG16(DX));
- WRITE16(tss+0x18,REG16(BX));
- WRITE16(tss+0x1a,REG16(SP));
- WRITE16(tss+0x1c,REG16(BP));
- WRITE16(tss+0x1e,REG16(SI));
- WRITE16(tss+0x20,REG16(DI));
- WRITE16(tss+0x22,m_sreg[ES].selector);
- WRITE16(tss+0x24,m_sreg[CS].selector);
- WRITE16(tss+0x26,m_sreg[SS].selector);
- WRITE16(tss+0x28,m_sreg[DS].selector);
-
- old_task = m_task.segment;
-
- /* Load task register with the selector of the incoming task */
- m_task.segment = selector;
- memset(&seg, 0, sizeof(seg));
- seg.selector = m_task.segment;
- i386_load_protected_mode_segment(&seg,nullptr);
- m_task.limit = seg.limit;
- m_task.base = seg.base;
- m_task.flags = seg.flags;
-
- /* Set TS bit in CR0 */
- m_cr[0] |= 0x08;
-
- /* Load incoming task state from the new task's TSS */
- tss = m_task.base;
- m_ldtr.segment = READ16(tss+0x2a) & 0xffff;
- seg.selector = m_ldtr.segment;
- i386_load_protected_mode_segment(&seg,nullptr);
- m_ldtr.limit = seg.limit;
- m_ldtr.base = seg.base;
- m_ldtr.flags = seg.flags;
- m_eip = READ16(tss+0x0e);
- set_flags(READ16(tss+0x10));
- REG16(AX) = READ16(tss+0x12);
- REG16(CX) = READ16(tss+0x14);
- REG16(DX) = READ16(tss+0x16);
- REG16(BX) = READ16(tss+0x18);
- REG16(SP) = READ16(tss+0x1a);
- REG16(BP) = READ16(tss+0x1c);
- REG16(SI) = READ16(tss+0x1e);
- REG16(DI) = READ16(tss+0x20);
- m_sreg[ES].selector = READ16(tss+0x22) & 0xffff;
- i386_load_segment_descriptor(ES);
- m_sreg[CS].selector = READ16(tss+0x24) & 0xffff;
- i386_load_segment_descriptor(CS);
- m_sreg[SS].selector = READ16(tss+0x26) & 0xffff;
- i386_load_segment_descriptor(SS);
- m_sreg[DS].selector = READ16(tss+0x28) & 0xffff;
- i386_load_segment_descriptor(DS);
-
- /* Set the busy bit in the new task's descriptor */
- if(selector & 0x0004)
- {
- ar_byte = READ8(m_ldtr.base + (selector & ~0x0007) + 5);
- WRITE8(m_ldtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02);
- }
- else
- {
- ar_byte = READ8(m_gdtr.base + (selector & ~0x0007) + 5);
- WRITE8(m_gdtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02);
- }
-
- /* For nested tasks, we write the outgoing task's selector to the back-link field of the new TSS,
- and set the NT flag in the EFLAGS register */
- if(nested != 0)
- {
- WRITE16(tss+0,old_task);
- m_NT = 1;
- }
- CHANGE_PC(m_eip);
-
- m_CPL = (m_sreg[SS].flags >> 5) & 3;
-// printf("286 Task Switch from selector %04x to %04x\n",old_task,selector);
-}
-
-void i386_device::i386_task_switch(uint16_t selector, uint8_t nested)
-{
- uint32_t tss;
- I386_SREG seg;
- uint16_t old_task;
- uint8_t ar_byte; // access rights byte
- uint32_t oldcr3 = m_cr[3];
-
- /* TODO: Task State Segment privilege checks */
-
- /* For tasks that aren't nested, clear the busy bit in the task's descriptor */
- if(nested == 0)
- {
- if(m_task.segment & 0x0004)
- {
- ar_byte = READ8(m_ldtr.base + (m_task.segment & ~0x0007) + 5);
- WRITE8(m_ldtr.base + (m_task.segment & ~0x0007) + 5,ar_byte & ~0x02);
- }
- else
- {
- ar_byte = READ8(m_gdtr.base + (m_task.segment & ~0x0007) + 5);
- WRITE8(m_gdtr.base + (m_task.segment & ~0x0007) + 5,ar_byte & ~0x02);
- }
- }
-
- /* Save the state of the current task in the current TSS (TR register base) */
- tss = m_task.base;
- WRITE32(tss+0x1c,m_cr[3]); // correct?
- WRITE32(tss+0x20,m_eip);
- WRITE32(tss+0x24,get_flags());
- WRITE32(tss+0x28,REG32(EAX));
- WRITE32(tss+0x2c,REG32(ECX));
- WRITE32(tss+0x30,REG32(EDX));
- WRITE32(tss+0x34,REG32(EBX));
- WRITE32(tss+0x38,REG32(ESP));
- WRITE32(tss+0x3c,REG32(EBP));
- WRITE32(tss+0x40,REG32(ESI));
- WRITE32(tss+0x44,REG32(EDI));
- WRITE32(tss+0x48,m_sreg[ES].selector);
- WRITE32(tss+0x4c,m_sreg[CS].selector);
- WRITE32(tss+0x50,m_sreg[SS].selector);
- WRITE32(tss+0x54,m_sreg[DS].selector);
- WRITE32(tss+0x58,m_sreg[FS].selector);
- WRITE32(tss+0x5c,m_sreg[GS].selector);
-
- old_task = m_task.segment;
-
- /* Load task register with the selector of the incoming task */
- m_task.segment = selector;
- memset(&seg, 0, sizeof(seg));
- seg.selector = m_task.segment;
- i386_load_protected_mode_segment(&seg,nullptr);
- m_task.limit = seg.limit;
- m_task.base = seg.base;
- m_task.flags = seg.flags;
-
- /* Set TS bit in CR0 */
- m_cr[0] |= 0x08;
-
- /* Load incoming task state from the new task's TSS */
- tss = m_task.base;
- m_ldtr.segment = READ32(tss+0x60) & 0xffff;
- seg.selector = m_ldtr.segment;
- i386_load_protected_mode_segment(&seg,nullptr);
- m_ldtr.limit = seg.limit;
- m_ldtr.base = seg.base;
- m_ldtr.flags = seg.flags;
- m_eip = READ32(tss+0x20);
- set_flags(READ32(tss+0x24));
- REG32(EAX) = READ32(tss+0x28);
- REG32(ECX) = READ32(tss+0x2c);
- REG32(EDX) = READ32(tss+0x30);
- REG32(EBX) = READ32(tss+0x34);
- REG32(ESP) = READ32(tss+0x38);
- REG32(EBP) = READ32(tss+0x3c);
- REG32(ESI) = READ32(tss+0x40);
- REG32(EDI) = READ32(tss+0x44);
- m_sreg[ES].selector = READ32(tss+0x48) & 0xffff;
- i386_load_segment_descriptor(ES);
- m_sreg[CS].selector = READ32(tss+0x4c) & 0xffff;
- i386_load_segment_descriptor(CS);
- m_sreg[SS].selector = READ32(tss+0x50) & 0xffff;
- i386_load_segment_descriptor(SS);
- m_sreg[DS].selector = READ32(tss+0x54) & 0xffff;
- i386_load_segment_descriptor(DS);
- m_sreg[FS].selector = READ32(tss+0x58) & 0xffff;
- i386_load_segment_descriptor(FS);
- m_sreg[GS].selector = READ32(tss+0x5c) & 0xffff;
- i386_load_segment_descriptor(GS);
- /* For nested tasks, we write the outgoing task's selector to the back-link field of the new TSS,
- and set the NT flag in the EFLAGS register before setting cr3 as the old tss address might be gone */
- if(nested != 0)
- {
- WRITE32(tss+0,old_task);
- m_NT = 1;
- }
- m_cr[3] = READ32(tss+0x1c); // CR3 (PDBR)
- if(oldcr3 != m_cr[3])
- vtlb_flush_dynamic();
-
- /* Set the busy bit in the new task's descriptor */
- if(selector & 0x0004)
- {
- ar_byte = READ8(m_ldtr.base + (selector & ~0x0007) + 5);
- WRITE8(m_ldtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02);
- }
- else
- {
- ar_byte = READ8(m_gdtr.base + (selector & ~0x0007) + 5);
- WRITE8(m_gdtr.base + (selector & ~0x0007) + 5,ar_byte | 0x02);
- }
-
- CHANGE_PC(m_eip);
-
- m_CPL = (m_sreg[SS].flags >> 5) & 3;
-// printf("386 Task Switch from selector %04x to %04x\n",old_task,selector);
-}
-
void i386_device::i386_check_irq_line()
{
if(!m_smm && m_smi)
@@ -1554,1442 +1528,6 @@ void i386_device::i386_check_irq_line()
}
}
-void i386_device::i386_protected_mode_jump(uint16_t seg, uint32_t off, int indirect, int operand32)
-{
- I386_SREG desc;
- I386_CALL_GATE call_gate;
- uint8_t CPL,DPL,RPL;
- uint8_t SetRPL;
- uint16_t segment = seg;
- uint32_t offset = off;
-
- /* Check selector is not null */
- if((segment & ~0x03) == 0)
- {
- logerror("JMP: Segment is null.\n");
- FAULT(FAULT_GP,0)
- }
- /* Selector is within descriptor table limit */
- if((segment & 0x04) == 0)
- {
- /* check GDT limit */
- if((segment & ~0x07) > (m_gdtr.limit))
- {
- logerror("JMP: Segment is past GDT limit.\n");
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- }
- else
- {
- /* check LDT limit */
- if((segment & ~0x07) > (m_ldtr.limit))
- {
- logerror("JMP: Segment is past LDT limit.\n");
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- }
- /* Determine segment type */
- memset(&desc, 0, sizeof(desc));
- desc.selector = segment;
- i386_load_protected_mode_segment(&desc,nullptr);
- CPL = m_CPL; // current privilege level
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- RPL = segment & 0x03; // requested privilege level
- if((desc.flags & 0x0018) == 0x0018)
- {
- /* code segment */
- if((desc.flags & 0x0004) == 0)
- {
- /* non-conforming */
- if(RPL > CPL)
- {
- logerror("JMP: RPL %i is less than CPL %i\n",RPL,CPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- if(DPL != CPL)
- {
- logerror("JMP: DPL %i is not equal CPL %i\n",DPL,CPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- }
- else
- {
- /* conforming */
- if(DPL > CPL)
- {
- logerror("JMP: DPL %i is less than CPL %i\n",DPL,CPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- }
- SetRPL = 1;
- if((desc.flags & 0x0080) == 0)
- {
- logerror("JMP: Segment is not present\n");
- FAULT(FAULT_NP,segment & 0xfffc)
- }
- if(offset > desc.limit)
- {
- logerror("JMP: Offset is past segment limit\n");
- FAULT(FAULT_GP,0)
- }
- }
- else
- {
- if((desc.flags & 0x0010) != 0)
- {
- logerror("JMP: Segment is a data segment\n");
- FAULT(FAULT_GP,segment & 0xfffc) // #GP (cannot execute code in a data segment)
- }
- else
- {
- switch(desc.flags & 0x000f)
- {
- case 0x01: // 286 Available TSS
- case 0x09: // 386 Available TSS
- logerror("JMP: Available 386 TSS at %08x\n",m_pc);
- memset(&desc, 0, sizeof(desc));
- desc.selector = segment;
- i386_load_protected_mode_segment(&desc,nullptr);
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- if(DPL < CPL)
- {
- logerror("JMP: TSS: DPL %i is less than CPL %i\n",DPL,CPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- if(DPL < RPL)
- {
- logerror("JMP: TSS: DPL %i is less than TSS RPL %i\n",DPL,RPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("JMP: TSS: Segment is not present\n");
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- if(desc.flags & 0x0008)
- i386_task_switch(desc.selector,0);
- else
- i286_task_switch(desc.selector,0);
- return;
- case 0x04: // 286 Call Gate
- case 0x0c: // 386 Call Gate
- //logerror("JMP: Call gate at %08x\n",m_pc);
- SetRPL = 1;
- memset(&call_gate, 0, sizeof(call_gate));
- call_gate.segment = segment;
- i386_load_call_gate(&call_gate);
- DPL = call_gate.dpl;
- if(DPL < CPL)
- {
- logerror("JMP: Call Gate: DPL %i is less than CPL %i\n",DPL,CPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- if(DPL < RPL)
- {
- logerror("JMP: Call Gate: DPL %i is less than RPL %i\n",DPL,RPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("JMP: Call Gate: Segment is not present\n");
- FAULT(FAULT_NP,segment & 0xfffc)
- }
- /* Now we examine the segment that the call gate refers to */
- if(call_gate.selector == 0)
- {
- logerror("JMP: Call Gate: Gate selector is null\n");
- FAULT(FAULT_GP,0)
- }
- if(call_gate.selector & 0x04)
- {
- if((call_gate.selector & ~0x07) > m_ldtr.limit)
- {
- logerror("JMP: Call Gate: Gate Selector is past LDT segment limit\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- }
- else
- {
- if((call_gate.selector & ~0x07) > m_gdtr.limit)
- {
- logerror("JMP: Call Gate: Gate Selector is past GDT segment limit\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- }
- desc.selector = call_gate.selector;
- i386_load_protected_mode_segment(&desc,nullptr);
- DPL = (desc.flags >> 5) & 0x03;
- if((desc.flags & 0x0018) != 0x18)
- {
- logerror("JMP: Call Gate: Gate does not point to a code segment\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- if((desc.flags & 0x0004) == 0)
- { // non-conforming
- if(DPL != CPL)
- {
- logerror("JMP: Call Gate: Gate DPL does not equal CPL\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- }
- else
- { // conforming
- if(DPL > CPL)
- {
- logerror("JMP: Call Gate: Gate DPL is greater than CPL\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("JMP: Call Gate: Gate Segment is not present\n");
- FAULT(FAULT_NP,call_gate.selector & 0xfffc)
- }
- if(call_gate.offset > desc.limit)
- {
- logerror("JMP: Call Gate: Gate offset is past Gate segment limit\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- segment = call_gate.selector;
- offset = call_gate.offset;
- break;
- case 0x05: // Task Gate
- logerror("JMP: Task gate at %08x\n",m_pc);
- memset(&call_gate, 0, sizeof(call_gate));
- call_gate.segment = segment;
- i386_load_call_gate(&call_gate);
- DPL = call_gate.dpl;
- if(DPL < CPL)
- {
- logerror("JMP: Task Gate: Gate DPL %i is less than CPL %i\n",DPL,CPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- if(DPL < RPL)
- {
- logerror("JMP: Task Gate: Gate DPL %i is less than CPL %i\n",DPL,CPL);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- if(call_gate.present == 0)
- {
- logerror("JMP: Task Gate: Gate is not present.\n");
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- /* Check the TSS that the task gate points to */
- desc.selector = call_gate.selector;
- i386_load_protected_mode_segment(&desc,nullptr);
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- RPL = call_gate.selector & 0x03; // requested privilege level
- if(call_gate.selector & 0x04)
- {
- logerror("JMP: Task Gate TSS: TSS must be global.\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- else
- {
- if((call_gate.selector & ~0x07) > m_gdtr.limit)
- {
- logerror("JMP: Task Gate TSS: TSS is past GDT limit.\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- }
- if((call_gate.ar & 0x000f) == 0x0009 || (call_gate.ar & 0x000f) == 0x0001)
- {
- logerror("JMP: Task Gate TSS: Segment is not an available TSS.\n");
- FAULT(FAULT_GP,call_gate.selector & 0xfffc)
- }
- if(call_gate.present == 0)
- {
- logerror("JMP: Task Gate TSS: TSS is not present.\n");
- FAULT(FAULT_NP,call_gate.selector & 0xfffc)
- }
- if(call_gate.ar & 0x08)
- i386_task_switch(call_gate.selector,0);
- else
- i286_task_switch(call_gate.selector,0);
- return;
- default: // invalid segment type
- logerror("JMP: Invalid segment type (%i) to jump to.\n",desc.flags & 0x000f);
- FAULT(FAULT_GP,segment & 0xfffc)
- }
- }
- }
-
- if(SetRPL != 0)
- segment = (segment & ~0x03) | m_CPL;
- if(operand32 == 0)
- m_eip = offset & 0x0000ffff;
- else
- m_eip = offset;
- m_sreg[CS].selector = segment;
- m_performed_intersegment_jump = 1;
- i386_load_segment_descriptor(CS);
- CHANGE_PC(m_eip);
-}
-
-void i386_device::i386_protected_mode_call(uint16_t seg, uint32_t off, int indirect, int operand32)
-{
- I386_SREG desc;
- I386_CALL_GATE gate;
- uint8_t SetRPL;
- uint8_t CPL, DPL, RPL;
- uint16_t selector = seg;
- uint32_t offset = off;
- int x;
-
- if((selector & ~0x03) == 0)
- {
- logerror("CALL (%08x): Selector is null.\n",m_pc);
- FAULT(FAULT_GP,0) // #GP(0)
- }
- if(selector & 0x04)
- {
- if((selector & ~0x07) > m_ldtr.limit)
- {
- logerror("CALL: Selector is past LDT limit.\n");
- FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
- }
- }
- else
- {
- if((selector & ~0x07) > m_gdtr.limit)
- {
- logerror("CALL: Selector is past GDT limit.\n");
- FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
- }
- }
-
- /* Determine segment type */
- memset(&desc, 0, sizeof(desc));
- desc.selector = selector;
- i386_load_protected_mode_segment(&desc,nullptr);
- CPL = m_CPL; // current privilege level
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- RPL = selector & 0x03; // requested privilege level
- if((desc.flags & 0x0018) == 0x18) // is a code segment
- {
- if(desc.flags & 0x0004)
- {
- /* conforming */
- if(DPL > CPL)
- {
- logerror("CALL: Code segment DPL %i is greater than CPL %i\n",DPL,CPL);
- FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
- }
- }
- else
- {
- /* non-conforming */
- if(RPL > CPL)
- {
- logerror("CALL: RPL %i is greater than CPL %i\n",RPL,CPL);
- FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
- }
- if(DPL != CPL)
- {
- logerror("CALL: Code segment DPL %i is not equal to CPL %i\n",DPL,CPL);
- FAULT(FAULT_GP,selector & ~0x03) // #GP(selector)
- }
- }
- SetRPL = 1;
- if((desc.flags & 0x0080) == 0)
- {
- logerror("CALL (%08x): Code segment is not present.\n",m_pc);
- FAULT(FAULT_NP,selector & ~0x03) // #NP(selector)
- }
- if (operand32 != 0) // if 32-bit
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) - 8 : (REG16(SP) - 8) & 0xffff);
- if(i386_limit_check(SS, offset))
- {
- logerror("CALL (%08x): Stack has no room for return address.\n",m_pc);
- FAULT(FAULT_SS,0) // #SS(0)
- }
- }
- else
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) - 4 : (REG16(SP) - 4) & 0xffff);
- if(i386_limit_check(SS, offset))
- {
- logerror("CALL (%08x): Stack has no room for return address.\n",m_pc);
- FAULT(FAULT_SS,0) // #SS(0)
- }
- }
- if(offset > desc.limit)
- {
- logerror("CALL: EIP is past segment limit.\n");
- FAULT(FAULT_GP,0) // #GP(0)
- }
- }
- else
- {
- /* special segment type */
- if(desc.flags & 0x0010)
- {
- logerror("CALL: Segment is a data segment.\n");
- FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector)
- }
- else
- {
- switch(desc.flags & 0x000f)
- {
- case 0x01: // Available 286 TSS
- case 0x09: // Available 386 TSS
- logerror("CALL: Available TSS at %08x\n",m_pc);
- if(DPL < CPL)
- {
- logerror("CALL: TSS: DPL is less than CPL.\n");
- FAULT(FAULT_TS,selector & ~0x03) // #TS(selector)
- }
- if(DPL < RPL)
- {
- logerror("CALL: TSS: DPL is less than RPL.\n");
- FAULT(FAULT_TS,selector & ~0x03) // #TS(selector)
- }
- if(desc.flags & 0x0002)
- {
- logerror("CALL: TSS: TSS is busy.\n");
- FAULT(FAULT_TS,selector & ~0x03) // #TS(selector)
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("CALL: TSS: Segment %02x is not present.\n",selector);
- FAULT(FAULT_NP,selector & ~0x03) // #NP(selector)
- }
- if(desc.flags & 0x08)
- i386_task_switch(desc.selector,1);
- else
- i286_task_switch(desc.selector,1);
- return;
- case 0x04: // 286 call gate
- case 0x0c: // 386 call gate
- if((desc.flags & 0x000f) == 0x04)
- operand32 = 0;
- else
- operand32 = 1;
- memset(&gate, 0, sizeof(gate));
- gate.segment = selector;
- i386_load_call_gate(&gate);
- DPL = gate.dpl;
- //logerror("CALL: Call gate at %08x (%i parameters)\n",m_pc,gate.dword_count);
- if(DPL < CPL)
- {
- logerror("CALL: Call gate DPL %i is less than CPL %i.\n",DPL,CPL);
- FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector)
- }
- if(DPL < RPL)
- {
- logerror("CALL: Call gate DPL %i is less than RPL %i.\n",DPL,RPL);
- FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector)
- }
- if(gate.present == 0)
- {
- logerror("CALL: Call gate is not present.\n");
- FAULT(FAULT_NP,desc.selector & ~0x03) // #GP(selector)
- }
- desc.selector = gate.selector;
- if((gate.selector & ~0x03) == 0)
- {
- logerror("CALL: Call gate: Segment is null.\n");
- FAULT(FAULT_GP,0) // #GP(0)
- }
- if(desc.selector & 0x04)
- {
- if((desc.selector & ~0x07) > m_ldtr.limit)
- {
- logerror("CALL: Call gate: Segment is past LDT limit\n");
- FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector)
- }
- }
- else
- {
- if((desc.selector & ~0x07) > m_gdtr.limit)
- {
- logerror("CALL: Call gate: Segment is past GDT limit\n");
- FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector)
- }
- }
- i386_load_protected_mode_segment(&desc,nullptr);
- if((desc.flags & 0x0018) != 0x18)
- {
- logerror("CALL: Call gate: Segment is not a code segment.\n");
- FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector)
- }
- DPL = ((desc.flags >> 5) & 0x03);
- if(DPL > CPL)
- {
- logerror("CALL: Call gate: Segment DPL %i is greater than CPL %i.\n",DPL,CPL);
- FAULT(FAULT_GP,desc.selector & ~0x03) // #GP(selector)
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("CALL (%08x): Code segment is not present.\n",m_pc);
- FAULT(FAULT_NP,desc.selector & ~0x03) // #NP(selector)
- }
- if(DPL < CPL && (desc.flags & 0x0004) == 0)
- {
- I386_SREG stack;
- I386_SREG temp;
- uint32_t oldSS,oldESP;
- /* more privilege */
- /* Check new SS segment for privilege level from TSS */
- memset(&stack, 0, sizeof(stack));
- stack.selector = i386_get_stack_segment(DPL);
- i386_load_protected_mode_segment(&stack,nullptr);
- if((stack.selector & ~0x03) == 0)
- {
- logerror("CALL: Call gate: TSS selector is null\n");
- FAULT(FAULT_TS,0) // #TS(0)
- }
- if(stack.selector & 0x04)
- {
- if((stack.selector & ~0x07) > m_ldtr.limit)
- {
- logerror("CALL: Call gate: TSS selector is past LDT limit\n");
- FAULT(FAULT_TS,stack.selector) // #TS(SS selector)
- }
- }
- else
- {
- if((stack.selector & ~0x07) > m_gdtr.limit)
- {
- logerror("CALL: Call gate: TSS selector is past GDT limit\n");
- FAULT(FAULT_TS,stack.selector) // #TS(SS selector)
- }
- }
- if((stack.selector & 0x03) != DPL)
- {
- logerror("CALL: Call gate: Stack selector RPL does not equal code segment DPL %i\n",DPL);
- FAULT(FAULT_TS,stack.selector) // #TS(SS selector)
- }
- if(((stack.flags >> 5) & 0x03) != DPL)
- {
- logerror("CALL: Call gate: Stack DPL does not equal code segment DPL %i\n",DPL);
- FAULT(FAULT_TS,stack.selector) // #TS(SS selector)
- }
- if((stack.flags & 0x0018) != 0x10 && (stack.flags & 0x0002))
- {
- logerror("CALL: Call gate: Stack segment is not a writable data segment\n");
- FAULT(FAULT_TS,stack.selector) // #TS(SS selector)
- }
- if((stack.flags & 0x0080) == 0)
- {
- logerror("CALL: Call gate: Stack segment is not present\n");
- FAULT(FAULT_SS,stack.selector) // #SS(SS selector)
- }
- uint32_t newESP = i386_get_stack_ptr(DPL);
- if(!stack.d)
- {
- newESP &= 0xffff;
- }
- if(operand32 != 0)
- {
- if(newESP < ((gate.dword_count & 0x1f) + 16))
- {
- logerror("CALL: Call gate: New stack has no room for 32-bit return address and parameters.\n");
- FAULT(FAULT_SS,0) // #SS(0)
- }
- if(gate.offset > desc.limit)
- {
- logerror("CALL: Call gate: EIP is past segment limit.\n");
- FAULT(FAULT_GP,0) // #GP(0)
- }
- }
- else
- {
- if(newESP < ((gate.dword_count & 0x1f) + 8))
- {
- logerror("CALL: Call gate: New stack has no room for 16-bit return address and parameters.\n");
- FAULT(FAULT_SS,0) // #SS(0)
- }
- if((gate.offset & 0xffff) > desc.limit)
- {
- logerror("CALL: Call gate: IP is past segment limit.\n");
- FAULT(FAULT_GP,0) // #GP(0)
- }
- }
- selector = gate.selector;
- offset = gate.offset;
-
- m_CPL = (stack.flags >> 5) & 0x03;
- /* check for page fault at new stack */
- WRITE_TEST(stack.base+newESP-1);
- /* switch to new stack */
- oldSS = m_sreg[SS].selector;
- m_sreg[SS].selector = i386_get_stack_segment(m_CPL);
- if(operand32 != 0)
- {
- oldESP = REG32(ESP);
- }
- else
- {
- oldESP = REG16(SP);
- }
- i386_load_segment_descriptor(SS );
- REG32(ESP) = newESP;
-
- if(operand32 != 0)
- {
- PUSH32SEG(oldSS);
- PUSH32(oldESP);
- }
- else
- {
- PUSH16(oldSS);
- PUSH16(oldESP & 0xffff);
- }
-
- memset(&temp, 0, sizeof(temp));
- temp.selector = oldSS;
- i386_load_protected_mode_segment(&temp,nullptr);
- /* copy parameters from old stack to new stack */
- for(x=(gate.dword_count & 0x1f)-1;x>=0;x--)
- {
- uint32_t addr = oldESP + (operand32?(x*4):(x*2));
- addr = temp.base + (temp.d?addr:(addr&0xffff));
- if(operand32)
- PUSH32(READ32(addr));
- else
- PUSH16(READ16(addr));
- }
- SetRPL = 1;
- }
- else
- {
- /* same privilege */
- if (operand32 != 0) // if 32-bit
- {
- uint32_t stkoff = (STACK_32BIT ? REG32(ESP) - 8 : (REG16(SP) - 8) & 0xffff);
- if(i386_limit_check(SS, stkoff))
- {
- logerror("CALL: Stack has no room for return address.\n");
- FAULT(FAULT_SS,0) // #SS(0)
- }
- selector = gate.selector;
- offset = gate.offset;
- }
- else
- {
- uint32_t stkoff = (STACK_32BIT ? REG32(ESP) - 4 : (REG16(SP) - 4) & 0xffff);
- if(i386_limit_check(SS, stkoff))
- {
- logerror("CALL: Stack has no room for return address.\n");
- FAULT(FAULT_SS,0) // #SS(0)
- }
- selector = gate.selector;
- offset = gate.offset & 0xffff;
- }
- if(offset > desc.limit)
- {
- logerror("CALL: EIP is past segment limit.\n");
- FAULT(FAULT_GP,0) // #GP(0)
- }
- SetRPL = 1;
- }
- break;
- case 0x05: // task gate
- logerror("CALL: Task gate at %08x\n",m_pc);
- memset(&gate, 0, sizeof(gate));
- gate.segment = selector;
- i386_load_call_gate(&gate);
- DPL = gate.dpl;
- if(DPL < CPL)
- {
- logerror("CALL: Task Gate: Gate DPL is less than CPL.\n");
- FAULT(FAULT_TS,selector & ~0x03) // #TS(selector)
- }
- if(DPL < RPL)
- {
- logerror("CALL: Task Gate: Gate DPL is less than RPL.\n");
- FAULT(FAULT_TS,selector & ~0x03) // #TS(selector)
- }
- if((gate.ar & 0x0080) == 0)
- {
- logerror("CALL: Task Gate: Gate is not present.\n");
- FAULT(FAULT_NP,selector & ~0x03) // #NP(selector)
- }
- /* Check the TSS that the task gate points to */
- desc.selector = gate.selector;
- i386_load_protected_mode_segment(&desc,nullptr);
- if(gate.selector & 0x04)
- {
- logerror("CALL: Task Gate: TSS is not global.\n");
- FAULT(FAULT_TS,gate.selector & ~0x03) // #TS(selector)
- }
- else
- {
- if((gate.selector & ~0x07) > m_gdtr.limit)
- {
- logerror("CALL: Task Gate: TSS is past GDT limit.\n");
- FAULT(FAULT_TS,gate.selector & ~0x03) // #TS(selector)
- }
- }
- if(desc.flags & 0x0002)
- {
- logerror("CALL: Task Gate: TSS is busy.\n");
- FAULT(FAULT_TS,gate.selector & ~0x03) // #TS(selector)
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("CALL: Task Gate: TSS is not present.\n");
- FAULT(FAULT_NP,gate.selector & ~0x03) // #TS(selector)
- }
- if(desc.flags & 0x08)
- i386_task_switch(desc.selector,1); // with nesting
- else
- i286_task_switch(desc.selector,1);
- return;
- default:
- logerror("CALL: Invalid special segment type (%i) to jump to.\n",desc.flags & 0x000f);
- FAULT(FAULT_GP,selector & ~0x07) // #GP(selector)
- }
- }
- }
-
- if(SetRPL != 0)
- selector = (selector & ~0x03) | m_CPL;
-
- uint32_t tempSP = REG32(ESP);
- try
- {
- // this is ugly but the alternative is worse
- if(operand32 == 0)
- {
- /* 16-bit operand size */
- PUSH16(m_sreg[CS].selector );
- PUSH16(m_eip & 0x0000ffff );
- m_sreg[CS].selector = selector;
- m_performed_intersegment_jump = 1;
- m_eip = offset;
- i386_load_segment_descriptor(CS);
- }
- else
- {
- /* 32-bit operand size */
- PUSH32SEG(m_sreg[CS].selector );
- PUSH32(m_eip );
- m_sreg[CS].selector = selector;
- m_performed_intersegment_jump = 1;
- m_eip = offset;
- i386_load_segment_descriptor(CS );
- }
- }
- catch(uint64_t e)
- {
- REG32(ESP) = tempSP;
- throw e;
- }
-
- CHANGE_PC(m_eip);
-}
-
-void i386_device::i386_protected_mode_retf(uint8_t count, uint8_t operand32)
-{
- uint32_t newCS, newEIP;
- I386_SREG desc;
- uint8_t CPL, RPL, DPL;
-
- uint32_t ea = i386_translate(SS, (STACK_32BIT)?REG32(ESP):REG16(SP), 0);
-
- if(operand32 == 0)
- {
- newEIP = READ16(ea) & 0xffff;
- newCS = READ16(ea+2) & 0xffff;
- }
- else
- {
- newEIP = READ32(ea);
- newCS = READ32(ea+4) & 0xffff;
- }
-
- memset(&desc, 0, sizeof(desc));
- desc.selector = newCS;
- i386_load_protected_mode_segment(&desc,nullptr);
- CPL = m_CPL; // current privilege level
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- RPL = newCS & 0x03;
-
- if(RPL < CPL)
- {
- logerror("RETF (%08x): Return segment RPL is less than CPL.\n",m_pc);
- FAULT(FAULT_GP,newCS & ~0x03)
- }
-
- if(RPL == CPL)
- {
- /* same privilege level */
- if((newCS & ~0x03) == 0)
- {
- logerror("RETF: Return segment is null.\n");
- FAULT(FAULT_GP,0)
- }
- if(newCS & 0x04)
- {
- if((newCS & ~0x07) >= m_ldtr.limit)
- {
- logerror("RETF: Return segment is past LDT limit.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- else
- {
- if((newCS & ~0x07) >= m_gdtr.limit)
- {
- logerror("RETF: Return segment is past GDT limit.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- if((desc.flags & 0x0018) != 0x0018)
- {
- logerror("RETF: Return segment is not a code segment.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- if(desc.flags & 0x0004)
- {
- if(DPL > RPL)
- {
- logerror("RETF: Conforming code segment DPL is greater than CS RPL.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- else
- {
- if(DPL != RPL)
- {
- logerror("RETF: Non-conforming code segment DPL does not equal CS RPL.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("RETF (%08x): Code segment is not present.\n",m_pc);
- FAULT(FAULT_NP,newCS & ~0x03)
- }
- if(newEIP > desc.limit)
- {
- logerror("RETF: EIP is past code segment limit.\n");
- FAULT(FAULT_GP,0)
- }
- if(operand32 == 0)
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+count+3) != 0)
- {
- logerror("RETF (%08x): SP is past stack segment limit.\n",m_pc);
- FAULT(FAULT_SS,0)
- }
- }
- else
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+count+7) != 0)
- {
- logerror("RETF: ESP is past stack segment limit.\n");
- FAULT(FAULT_SS,0)
- }
- }
- if(STACK_32BIT)
- REG32(ESP) += (operand32 ? 8 : 4) + count;
- else
- REG16(SP) += (operand32 ? 8 : 4) + count;
- }
- else if(RPL > CPL)
- {
- uint32_t newSS, newESP; // when changing privilege
- /* outer privilege level */
- if(operand32 == 0)
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+count+7) != 0)
- {
- logerror("RETF (%08x): SP is past stack segment limit.\n",m_pc);
- FAULT(FAULT_SS,0)
- }
- }
- else
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+count+15) != 0)
- {
- logerror("RETF: ESP is past stack segment limit.\n");
- FAULT(FAULT_SS,0)
- }
- }
- /* Check CS selector and descriptor */
- if((newCS & ~0x03) == 0)
- {
- logerror("RETF: CS segment is null.\n");
- FAULT(FAULT_GP,0)
- }
- if(newCS & 0x04)
- {
- if((newCS & ~0x07) >= m_ldtr.limit)
- {
- logerror("RETF: CS segment selector is past LDT limit.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- else
- {
- if((newCS & ~0x07) >= m_gdtr.limit)
- {
- logerror("RETF: CS segment selector is past GDT limit.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- if((desc.flags & 0x0018) != 0x0018)
- {
- logerror("RETF: CS segment is not a code segment.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- if(desc.flags & 0x0004)
- {
- if(DPL > RPL)
- {
- logerror("RETF: Conforming CS segment DPL is greater than return selector RPL.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- else
- {
- if(DPL != RPL)
- {
- logerror("RETF: Non-conforming CS segment DPL is not equal to return selector RPL.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("RETF: CS segment is not present.\n");
- FAULT(FAULT_NP,newCS & ~0x03)
- }
- if(newEIP > desc.limit)
- {
- logerror("RETF: EIP is past return CS segment limit.\n");
- FAULT(FAULT_GP,0)
- }
-
- if(operand32 == 0)
- {
- ea += count+4;
- newESP = READ16(ea) & 0xffff;
- newSS = READ16(ea+2) & 0xffff;
- }
- else
- {
- ea += count+8;
- newESP = READ32(ea);
- newSS = READ32(ea+4) & 0xffff;
- }
-
- /* Check SS selector and descriptor */
- desc.selector = newSS;
- i386_load_protected_mode_segment(&desc,nullptr);
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- if((newSS & ~0x07) == 0)
- {
- logerror("RETF: SS segment is null.\n");
- FAULT(FAULT_GP,0)
- }
- if(newSS & 0x04)
- {
- if((newSS & ~0x07) > m_ldtr.limit)
- {
- logerror("RETF (%08x): SS segment selector is past LDT limit.\n",m_pc);
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- }
- else
- {
- if((newSS & ~0x07) > m_gdtr.limit)
- {
- logerror("RETF (%08x): SS segment selector is past GDT limit.\n",m_pc);
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- }
- if((newSS & 0x03) != RPL)
- {
- logerror("RETF: SS segment RPL is not equal to CS segment RPL.\n");
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- if((desc.flags & 0x0018) != 0x0010 || (desc.flags & 0x0002) == 0)
- {
- logerror("RETF: SS segment is not a writable data segment.\n");
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- if(((desc.flags >> 5) & 0x03) != RPL)
- {
- logerror("RETF: SS DPL is not equal to CS segment RPL.\n");
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("RETF: SS segment is not present.\n");
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- m_CPL = newCS & 0x03;
-
- /* Load new SS:(E)SP */
- if(operand32 == 0)
- REG16(SP) = (newESP+count) & 0xffff;
- else
- REG32(ESP) = newESP+count;
- m_sreg[SS].selector = newSS;
- i386_load_segment_descriptor(SS );
-
- /* Check that DS, ES, FS and GS are valid for the new privilege level */
- i386_check_sreg_validity(DS);
- i386_check_sreg_validity(ES);
- i386_check_sreg_validity(FS);
- i386_check_sreg_validity(GS);
- }
-
- /* Load new CS:(E)IP */
- if(operand32 == 0)
- m_eip = newEIP & 0xffff;
- else
- m_eip = newEIP;
- m_sreg[CS].selector = newCS;
- i386_load_segment_descriptor(CS );
- CHANGE_PC(m_eip);
-}
-
-void i386_device::i386_protected_mode_iret(int operand32)
-{
- uint32_t newCS, newEIP;
- uint32_t newSS, newESP; // when changing privilege
- I386_SREG desc,stack;
- uint8_t CPL, RPL, DPL;
- uint32_t newflags;
- uint8_t IOPL = m_IOP1 | (m_IOP2 << 1);
-
- CPL = m_CPL;
- uint32_t ea = i386_translate(SS, (STACK_32BIT)?REG32(ESP):REG16(SP), 0);
- if(operand32 == 0)
- {
- newEIP = READ16(ea) & 0xffff;
- newCS = READ16(ea+2) & 0xffff;
- newflags = READ16(ea+4) & 0xffff;
- }
- else
- {
- newEIP = READ32(ea);
- newCS = READ32(ea+4) & 0xffff;
- newflags = READ32(ea+8);
- }
-
- if(V8086_MODE)
- {
- uint32_t oldflags = get_flags();
- if(IOPL != 3)
- {
- logerror("IRET (%08x): Is in Virtual 8086 mode and IOPL != 3.\n",m_pc);
- FAULT(FAULT_GP,0)
- }
- if(operand32 == 0)
- {
- m_eip = newEIP & 0xffff;
- m_sreg[CS].selector = newCS & 0xffff;
- newflags &= ~(3<<12);
- newflags |= (((oldflags>>12)&3)<<12); // IOPL cannot be changed in V86 mode
- set_flags((newflags & 0xffff) | (oldflags & ~0xffff));
- REG16(SP) += 6;
- }
- else
- {
- m_eip = newEIP;
- m_sreg[CS].selector = newCS & 0xffff;
- newflags &= ~(3<<12);
- newflags |= 0x20000 | (((oldflags>>12)&3)<<12); // IOPL and VM cannot be changed in V86 mode
- set_flags(newflags);
- REG32(ESP) += 12;
- }
- }
- else if(NESTED_TASK)
- {
- uint32_t task = READ32(m_task.base);
- /* Task Return */
- logerror("IRET (%08x): Nested task return.\n",m_pc);
- /* Check back-link selector in TSS */
- if(task & 0x04)
- {
- logerror("IRET: Task return: Back-linked TSS is not in GDT.\n");
- FAULT(FAULT_TS,task & ~0x03)
- }
- if((task & ~0x07) >= m_gdtr.limit)
- {
- logerror("IRET: Task return: Back-linked TSS is not in GDT.\n");
- FAULT(FAULT_TS,task & ~0x03)
- }
- memset(&desc, 0, sizeof(desc));
- desc.selector = task;
- i386_load_protected_mode_segment(&desc,nullptr);
- if((desc.flags & 0x001f) != 0x000b)
- {
- logerror("IRET (%08x): Task return: Back-linked TSS is not a busy TSS.\n",m_pc);
- FAULT(FAULT_TS,task & ~0x03)
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("IRET: Task return: Back-linked TSS is not present.\n");
- FAULT(FAULT_NP,task & ~0x03)
- }
- if(desc.flags & 0x08)
- i386_task_switch(desc.selector,0);
- else
- i286_task_switch(desc.selector,0);
- return;
- }
- else
- {
- if(newflags & 0x00020000) // if returning to virtual 8086 mode
- {
- // 16-bit iret can't reach here
- newESP = READ32(ea+12);
- newSS = READ32(ea+16) & 0xffff;
- /* Return to v86 mode */
- //logerror("IRET (%08x): Returning to Virtual 8086 mode.\n",m_pc);
- if(CPL != 0)
- {
- uint32_t oldflags = get_flags();
- newflags = (newflags & ~0x00003000) | (oldflags & 0x00003000);
- if(CPL > IOPL)
- newflags = (newflags & ~0x200 ) | (oldflags & 0x200);
- }
- set_flags(newflags);
- m_eip = POP32() & 0xffff; // high 16 bits are ignored
- m_sreg[CS].selector = POP32() & 0xffff;
- POP32(); // already set flags
- newESP = POP32();
- newSS = POP32() & 0xffff;
- m_sreg[ES].selector = POP32() & 0xffff;
- m_sreg[DS].selector = POP32() & 0xffff;
- m_sreg[FS].selector = POP32() & 0xffff;
- m_sreg[GS].selector = POP32() & 0xffff;
- REG32(ESP) = newESP; // all 32 bits are loaded
- m_sreg[SS].selector = newSS;
- i386_load_segment_descriptor(ES);
- i386_load_segment_descriptor(DS);
- i386_load_segment_descriptor(FS);
- i386_load_segment_descriptor(GS);
- i386_load_segment_descriptor(SS);
- m_CPL = 3; // Virtual 8086 tasks are always run at CPL 3
- }
- else
- {
- if(operand32 == 0)
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+3) != 0)
- {
- logerror("IRET: Data on stack is past SS limit.\n");
- FAULT(FAULT_SS,0)
- }
- }
- else
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+7) != 0)
- {
- logerror("IRET: Data on stack is past SS limit.\n");
- FAULT(FAULT_SS,0)
- }
- }
- RPL = newCS & 0x03;
- if(RPL < CPL)
- {
- logerror("IRET (%08x): Return CS RPL is less than CPL.\n",m_pc);
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- if(RPL == CPL)
- {
- /* return to same privilege level */
- if(operand32 == 0)
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+5) != 0)
- {
- logerror("IRET (%08x): Data on stack is past SS limit.\n",m_pc);
- FAULT(FAULT_SS,0)
- }
- }
- else
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+11) != 0)
- {
- logerror("IRET (%08x): Data on stack is past SS limit.\n",m_pc);
- FAULT(FAULT_SS,0)
- }
- }
- if((newCS & ~0x03) == 0)
- {
- logerror("IRET: Return CS selector is null.\n");
- FAULT(FAULT_GP,0)
- }
- if(newCS & 0x04)
- {
- if((newCS & ~0x07) >= m_ldtr.limit)
- {
- logerror("IRET: Return CS selector (%04x) is past LDT limit.\n",newCS);
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- else
- {
- if((newCS & ~0x07) >= m_gdtr.limit)
- {
- logerror("IRET: Return CS selector is past GDT limit.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- memset(&desc, 0, sizeof(desc));
- desc.selector = newCS;
- i386_load_protected_mode_segment(&desc,nullptr);
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- RPL = newCS & 0x03;
- if((desc.flags & 0x0018) != 0x0018)
- {
- logerror("IRET (%08x): Return CS segment is not a code segment.\n",m_pc);
- FAULT(FAULT_GP,newCS & ~0x07)
- }
- if(desc.flags & 0x0004)
- {
- if(DPL > RPL)
- {
- logerror("IRET: Conforming return CS DPL is greater than CS RPL.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- else
- {
- if(DPL != RPL)
- {
- logerror("IRET: Non-conforming return CS DPL is not equal to CS RPL.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("IRET: (%08x) Return CS segment is not present.\n", m_pc);
- FAULT(FAULT_NP,newCS & ~0x03)
- }
- if(newEIP > desc.limit)
- {
- logerror("IRET: Return EIP is past return CS limit.\n");
- FAULT(FAULT_GP,0)
- }
-
- if(CPL != 0)
- {
- uint32_t oldflags = get_flags();
- newflags = (newflags & ~0x00003000) | (oldflags & 0x00003000);
- if(CPL > IOPL)
- newflags = (newflags & ~0x200 ) | (oldflags & 0x200);
- }
-
- if(operand32 == 0)
- {
- m_eip = newEIP;
- m_sreg[CS].selector = newCS;
- set_flags(newflags);
- REG16(SP) += 6;
- }
- else
- {
- m_eip = newEIP;
- m_sreg[CS].selector = newCS & 0xffff;
- set_flags(newflags);
- REG32(ESP) += 12;
- }
- }
- else if(RPL > CPL)
- {
- /* return to outer privilege level */
- memset(&desc, 0, sizeof(desc));
- desc.selector = newCS;
- i386_load_protected_mode_segment(&desc,nullptr);
- DPL = (desc.flags >> 5) & 0x03; // descriptor privilege level
- RPL = newCS & 0x03;
- if(operand32 == 0)
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+9) != 0)
- {
- logerror("IRET: SP is past SS limit.\n");
- FAULT(FAULT_SS,0)
- }
- }
- else
- {
- uint32_t offset = (STACK_32BIT ? REG32(ESP) : REG16(SP));
- if(i386_limit_check(SS,offset+19) != 0)
- {
- logerror("IRET: ESP is past SS limit.\n");
- FAULT(FAULT_SS,0)
- }
- }
- /* Check CS selector and descriptor */
- if((newCS & ~0x03) == 0)
- {
- logerror("IRET: Return CS selector is null.\n");
- FAULT(FAULT_GP,0)
- }
- if(newCS & 0x04)
- {
- if((newCS & ~0x07) >= m_ldtr.limit)
- {
- logerror("IRET: Return CS selector is past LDT limit.\n");
- FAULT(FAULT_GP,newCS & ~0x03);
- }
- }
- else
- {
- if((newCS & ~0x07) >= m_gdtr.limit)
- {
- logerror("IRET: Return CS selector is past GDT limit.\n");
- FAULT(FAULT_GP,newCS & ~0x03);
- }
- }
- if((desc.flags & 0x0018) != 0x0018)
- {
- logerror("IRET: Return CS segment is not a code segment.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- if(desc.flags & 0x0004)
- {
- if(DPL > RPL)
- {
- logerror("IRET: Conforming return CS DPL is greater than CS RPL.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- else
- {
- if(DPL != RPL)
- {
- logerror("IRET: Non-conforming return CS DPL does not equal CS RPL.\n");
- FAULT(FAULT_GP,newCS & ~0x03)
- }
- }
- if((desc.flags & 0x0080) == 0)
- {
- logerror("IRET: Return CS segment is not present.\n");
- FAULT(FAULT_NP,newCS & ~0x03)
- }
-
- /* Check SS selector and descriptor */
- if(operand32 == 0)
- {
- newESP = READ16(ea+6) & 0xffff;
- newSS = READ16(ea+8) & 0xffff;
- }
- else
- {
- newESP = READ32(ea+12);
- newSS = READ32(ea+16) & 0xffff;
- }
- memset(&stack, 0, sizeof(stack));
- stack.selector = newSS;
- i386_load_protected_mode_segment(&stack,nullptr);
- DPL = (stack.flags >> 5) & 0x03;
- if((newSS & ~0x03) == 0)
- {
- logerror("IRET: Return SS selector is null.\n");
- FAULT(FAULT_GP,0)
- }
- if(newSS & 0x04)
- {
- if((newSS & ~0x07) >= m_ldtr.limit)
- {
- logerror("IRET: Return SS selector is past LDT limit.\n");
- FAULT(FAULT_GP,newSS & ~0x03);
- }
- }
- else
- {
- if((newSS & ~0x07) >= m_gdtr.limit)
- {
- logerror("IRET: Return SS selector is past GDT limit.\n");
- FAULT(FAULT_GP,newSS & ~0x03);
- }
- }
- if((newSS & 0x03) != RPL)
- {
- logerror("IRET: Return SS RPL is not equal to return CS RPL.\n");
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- if((stack.flags & 0x0018) != 0x0010)
- {
- logerror("IRET: Return SS segment is not a data segment.\n");
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- if((stack.flags & 0x0002) == 0)
- {
- logerror("IRET: Return SS segment is not writable.\n");
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- if(DPL != RPL)
- {
- logerror("IRET: Return SS DPL does not equal SS RPL.\n");
- FAULT(FAULT_GP,newSS & ~0x03)
- }
- if((stack.flags & 0x0080) == 0)
- {
- logerror("IRET: Return SS segment is not present.\n");
- FAULT(FAULT_NP,newSS & ~0x03)
- }
- if(newEIP > desc.limit)
- {
- logerror("IRET: EIP is past return CS limit.\n");
- FAULT(FAULT_GP,0)
- }
-
-// if(operand32 == 0)
-// REG16(SP) += 10;
-// else
-// REG32(ESP) += 20;
-
- // IOPL can only change if CPL is zero
- if(CPL != 0)
- {
- uint32_t oldflags = get_flags();
- newflags = (newflags & ~0x00003000) | (oldflags & 0x00003000);
- if(CPL > IOPL)
- newflags = (newflags & ~0x200 ) | (oldflags & 0x200);
- }
-
- if(operand32 == 0)
- {
- m_eip = newEIP & 0xffff;
- m_sreg[CS].selector = newCS;
- set_flags(newflags);
- REG16(SP) = newESP & 0xffff;
- m_sreg[SS].selector = newSS;
- }
- else
- {
- m_eip = newEIP;
- m_sreg[CS].selector = newCS & 0xffff;
- set_flags(newflags);
- REG32(ESP) = newESP;
- m_sreg[SS].selector = newSS & 0xffff;
- }
- m_CPL = newCS & 0x03;
- i386_load_segment_descriptor(SS);
-
- /* Check that DS, ES, FS and GS are valid for the new privilege level */
- i386_check_sreg_validity(DS);
- i386_check_sreg_validity(ES);
- i386_check_sreg_validity(FS);
- i386_check_sreg_validity(GS);
- }
- }
- }
-
- i386_load_segment_descriptor(CS);
- CHANGE_PC(m_eip);
-}
-
void i386_device::build_cycle_table()
{
int i, j;
@@ -3040,6 +1578,7 @@ void i386_device::report_invalid_modrm(const char* opcode, uint8_t modrm)
#include "pentops.hxx"
#include "x87ops.hxx"
#include "cpuidmsrs.hxx"
+#include "i386segs.hxx"
void i386_device::i386_decode_opcode()
@@ -4761,371 +3300,6 @@ void pentium3_device::device_reset()
}
/*****************************************************************************/
-/* 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);
-}
-
-template <class dt, offs_t xorle>
-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)
- 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 = m_data;
- 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);
-}
-
-template <class dt, offs_t xorle>
-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)
- nocache = true;
- if (mode & 1)
- nocache = true;
- if (nocache == false)
- {
- int offset = (address & 63) ^ xorle;
- dataw = cache.search<CacheWrite>(address);
- if (dataw)
- {
- *(dt *)(dataw + offset) = data;
- 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);
- *(dt *)(dataw + offset) = 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
- 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;
-
- 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);
-}
-
-
-/*****************************************************************************/
/* Intel Pentium 4 */
void pentium4_device::device_start()