/*
	Skelton for retropc emulator

	Origin : MAME 0.142
	Author : Takeda.Toshiya
	Date  : 2011.04.23-

	[ 80x86 ]
*/

#ifndef _LIBNEWDEV_I86_BASE_H_ 
#define _LIBNEWDEV_I86_BASE_H_

#include "../../common.h"
#include "./device.h"
#include "./i86_defs.h"
#define SIG_I86_TEST	0

class I86_BASE : public DEVICE
{
protected:
	/* ---------------------------------------------------------------------------
	contexts
	--------------------------------------------------------------------------- */
	
	DEVICE *d_mem, *d_io, *d_pic, *d_bios;
	DEVICE *d_mem_stored, *d_io_stored;
	
	/* ---------------------------------------------------------------------------
	registers
	--------------------------------------------------------------------------- */
	
	union REGTYPE {
		uint16_t w[8]; /* viewed as 16 bits registers */
		uint8_t b[16]; /* or as 8 bit registers       */
	} regs;
	uint32_t pc;
	uint32_t prevpc;
	uint32_t base[4];
	uint16_t sregs[4];
	uint16_t flags;
	int32_t AuxVal, OverVal, SignVal, ZeroVal, CarryVal, DirVal;
	uint8_t ParityVal;
	uint8_t TF, IF, MF;
	struct {
		struct {
			WREGS w[256];
			BREGS b[256];
		} reg;
		struct {
			WREGS w[256];
			BREGS b[256];
		} RM;
	} Mod_RM;
	
	int int_state;
	bool test_state;
	bool busreq, halted;
	
	int icount;
	int extra_icount;
	
	bool seg_prefix;	/* prefix segment indicator */
	uint8_t prefix_seg;	/* The prefixed segment */
	unsigned ea;
	uint16_t eo;		/* effective offset of the address (before segment is added) */
	uint8_t ea_seg;		/* effective segment of the address */
	
	struct i80x86_timing timing;
	/* ---------------------------------------------------------------------------
	opecode
	--------------------------------------------------------------------------- */
	
	// sub
	void interrupt(int num);
	void trap();
	unsigned GetEA(unsigned ModRM);
	void rotate_shift_byte(unsigned ModRM, unsigned cnt);
	void rotate_shift_word(unsigned ModRM, unsigned cnt);
	
	// opecode
	virtual void run_one_opecode();
	virtual void run_one_opecode_debugger();
	virtual void instruction(uint8_t code);
	
	virtual void _repc(int flagval);
	virtual void _call_far();
	virtual void _int();
	virtual void _aad();
	virtual void _call_d16();
	virtual void _rep(int flagval);
	virtual void _ffpre();
	
	inline void _add_br8();
	inline void _add_wr16();
	inline void _add_r8b();
	inline void _add_r16w();
	inline void _add_ald8();
	inline void _add_axd16();
	inline void _push_es();
	inline void _pop_es();
	inline void _or_br8();
	inline void _or_wr16();
	inline void _or_r8b();
	inline void _or_r16w();
	inline void _or_ald8();
	inline void _or_axd16();
	inline void _push_cs();
	inline void _adc_br8();
	inline void _adc_wr16();
	inline void _adc_r8b();
	inline void _adc_r16w();
	inline void _adc_ald8();
	inline void _adc_axd16();
	inline void _push_ss();
	inline void _pop_ss();
	inline void _sbb_br8();
	inline void _sbb_wr16();
	inline void _sbb_r8b();
	inline void _sbb_r16w();
	inline void _sbb_ald8();
	inline void _sbb_axd16();
	inline void _push_ds();
	inline void _pop_ds();
	inline void _and_br8();
	inline void _and_wr16();
	inline void _and_r8b();
	inline void _and_r16w();
	inline void _and_ald8();
	inline void _and_axd16();
	inline void _es();
	inline void _daa();
	inline void _sub_br8();
	inline void _sub_wr16();
	inline void _sub_r8b();
	inline void _sub_r16w();
	inline void _sub_ald8();
	inline void _sub_axd16();
	inline void _cs();
	inline void _das();
	inline void _xor_br8();
	inline void _xor_wr16();
	inline void _xor_r8b();
	inline void _xor_r16w();
	inline void _xor_ald8();
	inline void _xor_axd16();
	inline void _ss();
	inline void _aaa();
	inline void _cmp_br8();
	inline void _cmp_wr16();
	inline void _cmp_r8b();
	inline void _cmp_r16w();
	inline void _cmp_ald8();
	inline void _cmp_axd16();
	inline void _ds();
	inline void _aas();
	inline void _inc_ax();
	inline void _inc_cx();
	inline void _inc_dx();
	inline void _inc_bx();
	inline void _inc_sp();
	inline void _inc_bp();
	inline void _inc_si();
	inline void _inc_di();
	inline void _dec_ax();
	inline void _dec_cx();
	inline void _dec_dx();
	inline void _dec_bx();
	inline void _dec_sp();
	inline void _dec_bp();
	inline void _dec_si();
	inline void _dec_di();
	inline void _push_ax();
	inline void _push_cx();
	inline void _push_dx();
	inline void _push_bx();
	inline void _push_sp();
	inline void _push_bp();
	inline void _push_si();
	inline void _push_di();
	inline void _pop_ax();
	inline void _pop_cx();
	inline void _pop_dx();
	inline void _pop_bx();
	inline void _pop_sp();
	inline void _pop_bp();
	inline void _pop_si();
	inline void _pop_di();
	inline void _pusha();
	inline void _popa();
	inline void _bound();
	inline void _push_d16();
	inline void _imul_d16();
	inline void _push_d8();
	inline void _imul_d8();
	inline void _insb();
	inline void _insw();
	inline void _outsb();
	inline void _outsw();
	inline void _jo();
	inline void _jno();
	inline void _jb();
	inline void _jnb();
	inline void _jz();
	inline void _jnz();
	inline void _jbe();
	inline void _jnbe();
	inline void _js();
	inline void _jns();
	inline void _jp();
	inline void _jnp();
	inline void _jl();
	inline void _jnl();
	inline void _jle();
	inline void _jnle();
	inline void _80pre();
	inline void _81pre();
	inline void _82pre();
	inline void _83pre();
	inline void _test_br8();
	inline void _test_wr16();
	inline void _xchg_br8();
	inline void _xchg_wr16();
	inline void _mov_br8();
	inline void _mov_wr16();
	inline void _mov_r8b();
	inline void _mov_r16w();
	inline void _mov_wsreg();
	inline void _lea();
	inline void _mov_sregw();
	inline void _popw();
	inline void _nop();
	inline void _xchg_axcx();
	inline void _xchg_axdx();
	inline void _xchg_axbx();
	inline void _xchg_axsp();
	inline void _xchg_axbp();
	inline void _xchg_axsi();
	inline void _xchg_axdi();
	inline void _cbw();
	inline void _cwd();
	inline void _wait();
	inline void _pushf();
	inline void _popf();
	inline void _sahf();
	inline void _lahf();
	inline void _mov_aldisp();
	inline void _mov_axdisp();
	inline void _mov_dispal();
	inline void _mov_dispax();
	inline void _movsb();
	inline void _movsw();
	inline void _cmpsb();
	inline void _cmpsw();
	inline void _test_ald8();
	inline void _test_axd16();
	inline void _stosb();
	inline void _stosw();
	inline void _lodsb();
	inline void _lodsw();
	inline void _scasb();
	inline void _scasw();
	inline void _mov_ald8();
	inline void _mov_cld8();
	inline void _mov_dld8();
	inline void _mov_bld8();
	inline void _mov_ahd8();
	inline void _mov_chd8();
	inline void _mov_dhd8();
	inline void _mov_bhd8();
	inline void _mov_axd16();
	inline void _mov_cxd16();
	inline void _mov_dxd16();
	inline void _mov_bxd16();
	inline void _mov_spd16();
	inline void _mov_bpd16();
	inline void _mov_sid16();
	inline void _mov_did16();
	inline void _rotshft_bd8();
	inline void _rotshft_wd8();
	inline void _ret_d16();
	inline void _ret();
	inline void _les_dw();
	inline void _lds_dw();
	inline void _mov_bd8();
	inline void _mov_wd16();
	inline void _enter();
	inline void _leav();	// _leave()
	inline void _retf_d16();
	inline void _retf();
	inline void _int3();
	inline void _into();
	inline void _iret();
	inline void _rotshft_b();
	inline void _rotshft_w();
	inline void _rotshft_bcl();
	inline void _rotshft_wcl();
	inline void _aam();
	inline void _setalc();
	inline void _xlat();
	inline void _escape();
	inline void _loopne();
	inline void _loope();
	inline void _loop();
	inline void _jcxz();
	inline void _inal();
	inline void _inax();
	inline void _outal();
	inline void _outax();
	inline void _jmp_d16();
	inline void _jmp_far();
	inline void _jmp_d8();
	inline void _inaldx();
	inline void _inaxdx();
	inline void _outdxal();
	inline void _outdxax();
	inline void _lock();
	inline void _repne();
	inline void _repe();
	inline void _hlt();
	inline void _cmc();
	inline void _f6pre();
	inline void _f7pre();
	inline void _clc();
	inline void _stc();
	inline void _cli();
	inline void _sti();
	inline void _cld();
	inline void _std();
	inline void _fepre();
	inline void _invalid();
	
public:
	I86_BASE(VM* parent_vm, EMU* parent_emu) : DEVICE(parent_vm, parent_emu)
	{
		busreq = false;
		d_bios = NULL;
		d_pic = NULL;
		d_mem = d_mem_stored = NULL;
		d_io = d_io_stored = NULL;
		set_device_name(_T("i8086 CPU"));
	}
	~I86_BASE() {}
	
	// common functions
	virtual void initialize();
	virtual void reset();
	virtual int run(int clock);
	void write_signal(int id, uint32_t data, uint32_t mask);
	void set_intr_line(bool line, bool pending, uint32_t bit);
	void set_extra_clock(int clock)
	{
		extra_icount += clock;
	}
	int get_extra_clock()
	{
		return extra_icount;
	}
	uint32_t get_pc()
	{
		return prevpc;
	}
	uint32_t get_next_pc()
	{
		return pc;
	}
	void write_debug_data8(uint32_t addr, uint32_t data);
	uint32_t read_debug_data8(uint32_t addr);
	void write_debug_data16(uint32_t addr, uint32_t data);
	uint32_t read_debug_data16(uint32_t addr);
	void write_debug_io8(uint32_t addr, uint32_t data);
	uint32_t read_debug_io8(uint32_t addr);
	void write_debug_io16(uint32_t addr, uint32_t data);
	uint32_t read_debug_io16(uint32_t addr);
	bool write_debug_reg(const _TCHAR *reg, uint32_t data);
	void get_debug_regs_info(_TCHAR *buffer, size_t buffer_len);
	int debug_dasm(uint32_t pc, _TCHAR *buffer, size_t buffer_len);

	void save_state(FILEIO* state_fio);
	bool load_state(FILEIO* state_fio);
	
	// unique function
	void set_context_mem(DEVICE* device)
	{
		d_mem = device;
	}
	void set_context_io(DEVICE* device)
	{
		d_io = device;
	}
	void set_context_intr(DEVICE* device)
	{
		d_pic = device;
	}
	void set_context_bios(DEVICE* device)
	{
		d_bios = device;
	}
};
#include "i86_inlineops.h"

#endif
