-/*
- Skelton for retropc emulator
- Origin : MAME i386 core
- Author : Takeda.Toshiya
- Date : 2009.06.08-
-
- [ i386/i486/Pentium/MediaGX ]
-*/
+#include "vm.h"
+#include "../emu.h"
#include "i386.h"
#ifdef USE_DEBUGGER
#include "debugger.h"
#endif
-/* ----------------------------------------------------------------------------
- MAME i386
----------------------------------------------------------------------------- */
-
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
#pragma warning( disable : 4018 )
#pragma warning( disable : 4065 )
#define CPU_MODEL pentium4
#endif
-#ifndef __BIG_ENDIAN__
-#define LSB_FIRST
-#endif
-
#ifndef INLINE
#define INLINE inline
#endif
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
#ifdef I386_PSEUDO_BIOS
-#define BIOS_INT(num) if(cpustate->bios != NULL) { \
+#define BIOS_INT(num, __ret) if(cpustate->bios != NULL) { \
uint16_t regs[8], sregs[4]; \
+ __ret = false; \
regs[0] = REG16(AX); regs[1] = REG16(CX); regs[2] = REG16(DX); regs[3] = REG16(BX); \
regs[4] = REG16(SP); regs[5] = REG16(BP); regs[6] = REG16(SI); regs[7] = REG16(DI); \
sregs[0] = cpustate->sreg[ES].selector; sregs[1] = cpustate->sreg[CS].selector; \
sregs[2] = cpustate->sreg[SS].selector; sregs[3] = cpustate->sreg[DS].selector; \
int32_t ZeroFlag = cpustate->ZF, CarryFlag = cpustate->CF; \
+ printf("INT %x \n", num); \
if(cpustate->bios->bios_int_i86(num, regs, sregs, &ZeroFlag, &CarryFlag)) { \
REG16(AX) = regs[0]; REG16(CX) = regs[1]; REG16(DX) = regs[2]; REG16(BX) = regs[3]; \
REG16(SP) = regs[4]; REG16(BP) = regs[5]; REG16(SI) = regs[6]; REG16(DI) = regs[7]; \
cpustate->ZF = (UINT8)ZeroFlag; cpustate->CF = (UINT8)CarryFlag; \
- return; \
+ __ret = true; \
} \
}
-#define BIOS_CALL(address) if(cpustate->bios != NULL) { \
+#define BIOS_CALL(address,__ret) if(cpustate->bios != NULL) { \
uint16_t regs[8], sregs[4]; \
+ __ret = false; \
regs[0] = REG16(AX); regs[1] = REG16(CX); regs[2] = REG16(DX); regs[3] = REG16(BX); \
regs[4] = REG16(SP); regs[5] = REG16(BP); regs[6] = REG16(SI); regs[7] = REG16(DI); \
sregs[0] = cpustate->sreg[ES].selector; sregs[1] = cpustate->sreg[CS].selector; \
sregs[2] = cpustate->sreg[SS].selector; sregs[3] = cpustate->sreg[DS].selector; \
int32_t ZeroFlag = cpustate->ZF, CarryFlag = cpustate->CF; \
+ printf("CALL %08x %0x AX=%04x %02x %02x\n", cpustate, address, regs[0], REG8(AH), REG8(AL)); \
if(cpustate->bios->bios_call_i86(address, regs, sregs, &ZeroFlag, &CarryFlag)) { \
REG16(AX) = regs[0]; REG16(CX) = regs[1]; REG16(DX) = regs[2]; REG16(BX) = regs[3]; \
REG16(SP) = regs[4]; REG16(BP) = regs[5]; REG16(SI) = regs[6]; REG16(DI) = regs[7]; \
cpustate->ZF = (UINT8)ZeroFlag; cpustate->CF = (UINT8)CarryFlag; \
- return; \
+ __ret = true; \
} \
}
#endif
-static CPU_TRANSLATE(i386);
-
-#include "mame/lib/softfloat/softfloat.c"
-#include "mame/emu/cpu/vtlb.c"
-#include "mame/emu/cpu/i386/i386.c"
+//static CPU_TRANSLATE(i386);
+#include "mame/emu/cpu/vtlb.h"
+#include "mame/emu/cpu/i386/i386_exec.c"
#ifdef USE_DEBUGGER
#include "mame/emu/cpu/i386/i386dasm.c"
#endif
opaque = CPU_INIT_CALL(CPU_MODEL);
i386_state *cpustate = (i386_state *)opaque;
+
+ //I386_BASE::initialize();
cpustate->pic = d_pic;
cpustate->program = d_mem;
cpustate->io = d_io;
-#ifdef I386_PSEUDO_BIOS
cpustate->bios = d_bios;
-#endif
-#ifdef SINGLE_MODE_DMA
cpustate->dma = d_dma;
-#endif
+ cpustate->shutdown = 0;
+
#ifdef USE_DEBUGGER
cpustate->emu = emu;
cpustate->debugger = d_debugger;
cpustate->shutdown = 0;
}
-void I386::release()
-{
- i386_state *cpustate = (i386_state *)opaque;
- vtlb_free(cpustate->vtlb);
- free(opaque);
-}
-
void I386::reset()
{
i386_state *cpustate = (i386_state *)opaque;
int I386::run(int cycles)
{
i386_state *cpustate = (i386_state *)opaque;
- return CPU_EXECUTE_CALL(i386);
+ return cpu_execute((void *)cpustate, cycles);
+ //return CPU_EXECUTE_CALL(i386);
}
-void I386::write_signal(int id, uint32_t data, uint32_t mask)
+extern "C" {
+extern void I386OP(decode_opcode)(i386_state *cpustate);
+};
+
+int I386::cpu_execute(void *p, int cycles)
{
- i386_state *cpustate = (i386_state *)opaque;
-
- if(id == SIG_CPU_NMI) {
- i386_set_irq_line(cpustate, INPUT_LINE_NMI, (data & mask) ? HOLD_LINE : CLEAR_LINE);
- } else if(id == SIG_CPU_IRQ) {
- i386_set_irq_line(cpustate, INPUT_LINE_IRQ, (data & mask) ? HOLD_LINE : CLEAR_LINE);
- } else if(id == SIG_CPU_BUSREQ) {
- cpustate->busreq = (data & mask) ? 1 : 0;
- } else if(id == SIG_I386_A20) {
- i386_set_a20_line(cpustate, data & mask);
+ i386_state *cpustate = (i386_state *)p;
+ CHANGE_PC(cpustate,cpustate->eip);
+
+ if (cpustate->halted || cpustate->busreq)
+ {
+#ifdef SINGLE_MODE_DMA
+ if(cpustate->dma != NULL) {
+ cpustate->dma->do_dma();
+ }
+#endif
+ if (cycles == -1) {
+ int passed_cycles = max(1, cpustate->extra_cycles);
+ // this is main cpu, cpustate->cycles is not used
+ /*cpustate->cycles = */cpustate->extra_cycles = 0;
+ cpustate->tsc += passed_cycles;
+ return passed_cycles;
+ } else {
+ cpustate->cycles += cycles;
+ cpustate->base_cycles = cpustate->cycles;
+
+ /* adjust for any interrupts that came in */
+ cpustate->cycles -= cpustate->extra_cycles;
+ cpustate->extra_cycles = 0;
+
+ /* if busreq is raised, spin cpu while remained clock */
+ if (cpustate->cycles > 0) {
+ cpustate->cycles = 0;
+ }
+ int passed_cycles = cpustate->base_cycles - cpustate->cycles;
+ cpustate->tsc += passed_cycles;
+ return passed_cycles;
+ }
}
-}
-void I386::set_intr_line(bool line, bool pending, uint32_t bit)
-{
- i386_state *cpustate = (i386_state *)opaque;
- i386_set_irq_line(cpustate, INPUT_LINE_IRQ, line ? HOLD_LINE : CLEAR_LINE);
-}
+ if (cycles == -1) {
+ cpustate->cycles = 1;
+ } else {
+ cpustate->cycles += cycles;
+ }
+ cpustate->base_cycles = cpustate->cycles;
-void I386::set_extra_clock(int cycles)
-{
- i386_state *cpustate = (i386_state *)opaque;
- cpustate->extra_cycles += cycles;
-}
+ /* adjust for any interrupts that came in */
+ cpustate->cycles -= cpustate->extra_cycles;
+ cpustate->extra_cycles = 0;
-int I386::get_extra_clock()
-{
- i386_state *cpustate = (i386_state *)opaque;
- return cpustate->extra_cycles;
-}
+ while( cpustate->cycles > 0 && !cpustate->busreq )
+ {
+#ifdef USE_DEBUGGER
+ bool now_debugging = cpustate->debugger->now_debugging;
+ if(now_debugging) {
+ cpustate->debugger->check_break_points(cpustate->pc);
+ if(cpustate->debugger->now_suspended) {
+ cpustate->emu->mute_sound();
+ while(cpustate->debugger->now_debugging && cpustate->debugger->now_suspended) {
+ cpustate->emu->sleep(10);
+ }
+ }
+ if(cpustate->debugger->now_debugging) {
+ cpustate->program = cpustate->io = cpustate->debugger;
+ } else {
+ now_debugging = false;
+ }
+ i386_check_irq_line(cpustate);
+ cpustate->operand_size = cpustate->sreg[CS].d;
+ cpustate->xmm_operand_size = 0;
+ cpustate->address_size = cpustate->sreg[CS].d;
+ cpustate->operand_prefix = 0;
+ cpustate->address_prefix = 0;
+
+ cpustate->ext = 1;
+ int old_tf = cpustate->TF;
+
+ cpustate->segment_prefix = 0;
+ cpustate->prev_eip = cpustate->eip;
+ cpustate->prev_pc = cpustate->pc;
+
+ if(cpustate->delayed_interrupt_enable != 0)
+ {
+ cpustate->IF = 1;
+ cpustate->delayed_interrupt_enable = 0;
+ }
+#ifdef DEBUG_MISSING_OPCODE
+ cpustate->opcode_bytes_length = 0;
+ cpustate->opcode_pc = cpustate->pc;
+#endif
+ try
+ {
+ I386OP(decode_opcode)(cpustate);
+ printf("%04x\n", REG16(AX));
+ if(cpustate->TF && old_tf)
+ {
+ cpustate->prev_eip = cpustate->eip;
+ cpustate->ext = 1;
+ i386_trap(cpustate,1,0,0);
+ }
+ if(cpustate->lock && (cpustate->opcode != 0xf0))
+ cpustate->lock = false;
+ }
+ catch(UINT64 e)
+ {
+ cpustate->ext = 1;
+ i386_trap_with_error(cpustate,e&0xffffffff,0,0,e>>32);
+ }
+#ifdef SINGLE_MODE_DMA
+ if(cpustate->dma != NULL) {
+ cpustate->dma->do_dma();
+ }
+#endif
+ /* adjust for any interrupts that came in */
+ cpustate->cycles -= cpustate->extra_cycles;
+ cpustate->extra_cycles = 0;
+
+ if(now_debugging) {
+ if(!cpustate->debugger->now_going) {
+ cpustate->debugger->now_suspended = true;
+ }
+ cpustate->program = cpustate->program_stored;
+ cpustate->io = cpustate->io_stored;
+ }
+ } else {
+#endif
+ i386_check_irq_line(cpustate);
+ cpustate->operand_size = cpustate->sreg[CS].d;
+ cpustate->xmm_operand_size = 0;
+ cpustate->address_size = cpustate->sreg[CS].d;
+ cpustate->operand_prefix = 0;
+ cpustate->address_prefix = 0;
+
+ cpustate->ext = 1;
+ int old_tf = cpustate->TF;
+
+ cpustate->segment_prefix = 0;
+ cpustate->prev_eip = cpustate->eip;
+ cpustate->prev_pc = cpustate->pc;
+
+ if(cpustate->delayed_interrupt_enable != 0)
+ {
+ cpustate->IF = 1;
+ cpustate->delayed_interrupt_enable = 0;
+ }
+#ifdef DEBUG_MISSING_OPCODE
+ cpustate->opcode_bytes_length = 0;
+ cpustate->opcode_pc = cpustate->pc;
+#endif
+ try
+ {
+ I386OP(decode_opcode)(cpustate);
+ printf("%04x\n", REG16(AX));
+ if(cpustate->TF && old_tf)
+ {
+ cpustate->prev_eip = cpustate->eip;
+ cpustate->ext = 1;
+ i386_trap(cpustate,1,0,0);
+ }
+ if(cpustate->lock && (cpustate->opcode != 0xf0))
+ cpustate->lock = false;
+ }
+ catch(UINT64 e)
+ {
+ cpustate->ext = 1;
+ i386_trap_with_error(cpustate,e&0xffffffff,0,0,e>>32);
+ }
+#ifdef SINGLE_MODE_DMA
+ if(cpustate->dma != NULL) {
+ cpustate->dma->do_dma();
+ }
+#endif
+ /* adjust for any interrupts that came in */
+ cpustate->cycles -= cpustate->extra_cycles;
+ cpustate->extra_cycles = 0;
+#ifdef USE_DEBUGGER
+ }
+#endif
+ }
-uint32_t I386::get_pc()
-{
- i386_state *cpustate = (i386_state *)opaque;
- return cpustate->prev_pc;
+ /* if busreq is raised, spin cpu while remained clock */
+ if (cpustate->cycles > 0 && cpustate->busreq) {
+ cpustate->cycles = 0;
+ }
+ int passed_cycles = cpustate->base_cycles - cpustate->cycles;
+ cpustate->tsc += passed_cycles;
+ return passed_cycles;
}
-uint32_t I386::get_next_pc()
-{
- i386_state *cpustate = (i386_state *)opaque;
- return cpustate->pc;
-}
#ifdef USE_DEBUGGER
void I386::write_debug_data8(uint32_t addr, uint32_t data)
}
#endif
-void I386::set_address_mask(uint32_t mask)
-{
- i386_state *cpustate = (i386_state *)opaque;
- cpustate->a20_mask = mask;
-}
-
-uint32_t I386::get_address_mask()
-{
- i386_state *cpustate = (i386_state *)opaque;
- return cpustate->a20_mask;
-}
-
-void I386::set_shutdown_flag(int shutdown)
-{
- i386_state *cpustate = (i386_state *)opaque;
- cpustate->shutdown = shutdown;
-}
-
-int I386::get_shutdown_flag()
-{
- i386_state *cpustate = (i386_state *)opaque;
- return cpustate->shutdown;
-}
-
-#define STATE_VERSION 1
-
void I386::save_state(FILEIO* state_fio)
{
- state_fio->FputUint32(STATE_VERSION);
- state_fio->FputInt32(this_device_id);
-
- state_fio->Fwrite(opaque, sizeof(i386_state), 1);
+ I386_BASE::save_state(state_fio);
}
-bool I386::load_state(FILEIO* state_fio)
+bool I386::load_state(FILEIO *state_fio)
{
- if(state_fio->FgetUint32() != STATE_VERSION) {
- return false;
- }
- if(state_fio->FgetInt32() != this_device_id) {
- return false;
- }
- state_fio->Fread(opaque, sizeof(i386_state), 1);
+ if(!I386_BASE::load_state(state_fio)) return false;
- // post process
i386_state *cpustate = (i386_state *)opaque;
- cpustate->pic = d_pic;
- cpustate->program = d_mem;
- cpustate->io = d_io;
-#ifdef I86_PSEUDO_BIOS
- cpustate->bios = d_bios;
-#endif
-#ifdef SINGLE_MODE_DMA
- cpustate->dma = d_dma;
-#endif
#ifdef USE_DEBUGGER
cpustate->emu = emu;
cpustate->debugger = d_debugger;
#endif
return true;
}
-
--- /dev/null
+/*
+ Skelton for retropc emulator
+
+ Origin : MAME i386 core
+ Author : Takeda.Toshiya
+ Date : 2009.06.08-
+
+ [ i386/i486/Pentium/MediaGX ]
+*/
+
+#include "i386_base.h"
+
+/* ----------------------------------------------------------------------------
+ MAME i386
+---------------------------------------------------------------------------- */
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#pragma warning( disable : 4018 )
+#pragma warning( disable : 4065 )
+#pragma warning( disable : 4146 )
+#pragma warning( disable : 4244 )
+#pragma warning( disable : 4996 )
+#endif
+
+#ifndef __BIG_ENDIAN__
+#define LSB_FIRST
+#endif
+
+extern "C" {
+#ifndef INLINE
+#define INLINE inline
+#endif
+
+#define U64(v) UINT64(v)
+
+#define fatalerror(...) exit(1)
+#define logerror(...)
+#define popmessage(...)
+
+/*****************************************************************************/
+/* src/emu/devcpu.h */
+
+/*****************************************************************************/
+/* src/emu/didisasm.h */
+
+// Disassembler constants
+const UINT32 DASMFLAG_SUPPORTED = 0x80000000; // are disassembly flags supported?
+const UINT32 DASMFLAG_STEP_OUT = 0x40000000; // this instruction should be the end of a step out sequence
+const UINT32 DASMFLAG_STEP_OVER = 0x20000000; // this instruction should be stepped over by setting a breakpoint afterwards
+const UINT32 DASMFLAG_OVERINSTMASK = 0x18000000; // number of extra instructions to skip when stepping over
+const UINT32 DASMFLAG_OVERINSTSHIFT = 27; // bits to shift after masking to get the value
+const UINT32 DASMFLAG_LENGTHMASK = 0x0000ffff; // the low 16-bits contain the actual length
+
+/*****************************************************************************/
+/* src/emu/diexec.h */
+
+// I/O line states
+enum line_state
+{
+ CLEAR_LINE = 0, // clear (a fired or held) line
+ ASSERT_LINE, // assert an interrupt immediately
+ HOLD_LINE, // hold interrupt line until acknowledged
+ PULSE_LINE // pulse interrupt line instantaneously (only for NMI, RESET)
+};
+
+enum
+{
+ INPUT_LINE_IRQ = 0,
+ INPUT_LINE_NMI
+};
+
+/*****************************************************************************/
+/* src/emu/dimemory.h */
+
+// Translation intentions
+const int TRANSLATE_TYPE_MASK = 0x03; // read write or fetch
+const int TRANSLATE_USER_MASK = 0x04; // user mode or fully privileged
+const int TRANSLATE_DEBUG_MASK = 0x08; // debug mode (no side effects)
+
+const int TRANSLATE_READ = 0; // translate for read
+const int TRANSLATE_WRITE = 1; // translate for write
+const int TRANSLATE_FETCH = 2; // translate for instruction fetch
+const int TRANSLATE_READ_USER = (TRANSLATE_READ | TRANSLATE_USER_MASK);
+const int TRANSLATE_WRITE_USER = (TRANSLATE_WRITE | TRANSLATE_USER_MASK);
+const int TRANSLATE_FETCH_USER = (TRANSLATE_FETCH | TRANSLATE_USER_MASK);
+const int TRANSLATE_READ_DEBUG = (TRANSLATE_READ | TRANSLATE_DEBUG_MASK);
+const int TRANSLATE_WRITE_DEBUG = (TRANSLATE_WRITE | TRANSLATE_DEBUG_MASK);
+const int TRANSLATE_FETCH_DEBUG = (TRANSLATE_FETCH | TRANSLATE_DEBUG_MASK);
+
+/*****************************************************************************/
+/* src/emu/emucore.h */
+
+// constants for expression endianness
+enum endianness_t
+{
+ ENDIANNESS_LITTLE,
+ ENDIANNESS_BIG
+};
+
+// declare native endianness to be one or the other
+#ifdef LSB_FIRST
+const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_LITTLE;
+#else
+const endianness_t ENDIANNESS_NATIVE = ENDIANNESS_BIG;
+#endif
+// endian-based value: first value is if 'endian' is little-endian, second is if 'endian' is big-endian
+#define ENDIAN_VALUE_LE_BE(endian,leval,beval) (((endian) == ENDIANNESS_LITTLE) ? (leval) : (beval))
+// endian-based value: first value is if native endianness is little-endian, second is if native is big-endian
+#define NATIVE_ENDIAN_VALUE_LE_BE(leval,beval) ENDIAN_VALUE_LE_BE(ENDIANNESS_NATIVE, leval, beval)
+// endian-based value: first value is if 'endian' matches native, second is if 'endian' doesn't match native
+#define ENDIAN_VALUE_NE_NNE(endian,leval,beval) (((endian) == ENDIANNESS_NATIVE) ? (neval) : (nneval))
+
+/*****************************************************************************/
+/* src/emu/memory.h */
+
+// address spaces
+enum address_spacenum
+{
+ AS_0, // first address space
+ AS_1, // second address space
+ AS_2, // third address space
+ AS_3, // fourth address space
+ ADDRESS_SPACES, // maximum number of address spaces
+
+ // alternate address space names for common use
+ AS_PROGRAM = AS_0, // program address space
+ AS_DATA = AS_1, // data address space
+ AS_IO = AS_2 // I/O address space
+};
+
+// offsets and addresses are 32-bit (for now...)
+typedef UINT32 offs_t;
+
+/*****************************************************************************/
+/* src/osd/osdcomm.h */
+
+/* Highly useful macro for compile-time knowledge of an array size */
+#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))
+
+static CPU_TRANSLATE(i386);
+}
+#include "mame/lib/softfloat/softfloat.c"
+#include "mame/emu/cpu/vtlb.c"
+#include "mame/emu/cpu/i386/i386.c"
+
+
+void I386_BASE::initialize()
+{
+// i386_state *cpustate = (i386_state *)opaque;
+// cpustate->pic = d_pic;
+// cpustate->program = d_mem;
+// cpustate->io = d_io;
+// cpustate->bios = d_bios;
+// cpustate->dma = d_dma;
+// cpustate->shutdown = 0;
+}
+
+void I386_BASE::release()
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ vtlb_free(cpustate->vtlb);
+ free(opaque);
+}
+
+void I386_BASE::reset()
+{
+ //i386_state *cpustate = (i386_state *)opaque;
+ //CPU_RESET_CALL(CPU_MODEL);
+}
+
+int I386_BASE::run(int cycles)
+{
+ //i386_state *cpustate = (i386_state *)opaque;
+ return 0;
+ //return CPU_EXECUTE_CALL(i386);
+}
+
+void I386_BASE::write_signal(int id, uint32_t data, uint32_t mask)
+{
+ i386_state *cpustate = (i386_state *)opaque;
+
+ if(id == SIG_CPU_NMI) {
+ i386_set_irq_line(cpustate, INPUT_LINE_NMI, (data & mask) ? HOLD_LINE : CLEAR_LINE);
+ } else if(id == SIG_CPU_IRQ) {
+ i386_set_irq_line(cpustate, INPUT_LINE_IRQ, (data & mask) ? HOLD_LINE : CLEAR_LINE);
+ } else if(id == SIG_CPU_BUSREQ) {
+ cpustate->busreq = (data & mask) ? 1 : 0;
+ } else if(id == SIG_I386_A20) {
+ i386_set_a20_line(cpustate, data & mask);
+ }
+}
+
+void I386_BASE::set_intr_line(bool line, bool pending, uint32_t bit)
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ i386_set_irq_line(cpustate, INPUT_LINE_IRQ, line ? HOLD_LINE : CLEAR_LINE);
+}
+
+void I386_BASE::set_extra_clock(int cycles)
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ cpustate->extra_cycles += cycles;
+}
+
+int I386_BASE::get_extra_clock()
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ return cpustate->extra_cycles;
+}
+
+uint32_t I386_BASE::get_pc()
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ return cpustate->prev_pc;
+}
+
+uint32_t I386_BASE::get_next_pc()
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ return cpustate->pc;
+}
+
+void I386_BASE::set_address_mask(uint32_t mask)
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ cpustate->a20_mask = mask;
+}
+
+uint32_t I386_BASE::get_address_mask()
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ return cpustate->a20_mask;
+}
+
+void I386_BASE::set_shutdown_flag(int shutdown)
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ cpustate->shutdown = shutdown;
+}
+
+int I386_BASE::get_shutdown_flag()
+{
+ i386_state *cpustate = (i386_state *)opaque;
+ return cpustate->shutdown;
+}
+
+#define STATE_VERSION 1
+
+void I386_BASE::save_state(FILEIO* state_fio)
+{
+ state_fio->FputUint32(STATE_VERSION);
+ state_fio->FputInt32(this_device_id);
+
+ state_fio->Fwrite(opaque, sizeof(i386_state), 1);
+}
+
+bool I386_BASE::load_state(FILEIO* state_fio)
+{
+ if(state_fio->FgetUint32() != STATE_VERSION) {
+ return false;
+ }
+ if(state_fio->FgetInt32() != this_device_id) {
+ return false;
+ }
+ state_fio->Fread(opaque, sizeof(i386_state), 1);
+
+ // post process
+ i386_state *cpustate = (i386_state *)opaque;
+ cpustate->pic = d_pic;
+ cpustate->program = d_mem;
+ cpustate->io = d_io;
+
+ cpustate->bios = d_bios;
+ cpustate->dma = d_dma;
+
+ return true;
+}
+