#ifndef __I8085_H__
#define __I8085_H__


/***************************************************************************
    CONSTANTS
***************************************************************************/

enum
{
	I8085_PC, I8085_SP, I8085_AF, I8085_BC, I8085_DE, I8085_HL,
	I8085_A, I8085_B, I8085_C, I8085_D, I8085_E, I8085_F, I8085_H, I8085_L,
	I8085_STATUS, I8085_SOD, I8085_SID, I8085_INTE,
	I8085_HALT, I8085_IM,

	I8085_GENPC = STATE_GENPC,
	I8085_GENSP = STATE_GENSP,
	I8085_GENPCBASE = STATE_GENPCBASE
};

#define I8085_INTR_LINE     0
#define I8085_RST55_LINE    1
#define I8085_RST65_LINE    2
#define I8085_RST75_LINE    3

#define I8085_STATUS_INTA   0x01
#define I8085_STATUS_WO     0x02
#define I8085_STATUS_STACK  0x04
#define I8085_STATUS_HLTA   0x08
#define I8085_STATUS_OUT    0x10
#define I8085_STATUS_M1     0x20
#define I8085_STATUS_INP    0x40
#define I8085_STATUS_MEMR   0x80


/* STATUS changed callback */
#define MCFG_I8085A_STATUS(_devcb) \
	i8085a_cpu_device::set_out_status_func(*device, DEVCB_##_devcb);

/* INTE changed callback */
#define MCFG_I8085A_INTE(_devcb) \
	i8085a_cpu_device::set_out_inte_func(*device, DEVCB_##_devcb);

/* SID changed callback (8085A only) */
#define MCFG_I8085A_SID(_devcb) \
	i8085a_cpu_device::set_in_sid_func(*device, DEVCB_##_devcb);

/* SOD changed callback (8085A only) */
#define MCFG_I8085A_SOD(_devcb) \
	i8085a_cpu_device::set_out_sod_func(*device, DEVCB_##_devcb);


class i8085a_cpu_device :  public cpu_device
{
public:
	// construction/destruction
	i8085a_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
	i8085a_cpu_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int cputype);

	// static configuration helpers
	template<class _Object> static devcb_base &set_out_status_func(device_t &device, _Object object) { return downcast<i8085a_cpu_device &>(device).m_out_status_func.set_callback(object); }
	template<class _Object> static devcb_base &set_out_inte_func(device_t &device, _Object object) { return downcast<i8085a_cpu_device &>(device).m_out_inte_func.set_callback(object); }
	template<class _Object> static devcb_base &set_in_sid_func(device_t &device, _Object object) { return downcast<i8085a_cpu_device &>(device).m_in_sid_func.set_callback(object); }
	template<class _Object> static devcb_base &set_out_sod_func(device_t &device, _Object object) { return downcast<i8085a_cpu_device &>(device).m_out_sod_func.set_callback(object); }

protected:
	// device-level overrides
	virtual void device_start();
	virtual void device_reset();

	// device_execute_interface overrides
	virtual UINT32 execute_min_cycles() const { return 4; }
	virtual UINT32 execute_max_cycles() const { return 16; }
	virtual UINT32 execute_input_lines() const { return 4; }
	virtual UINT32 execute_default_irq_vector() const { return 0xff; }
	virtual void execute_run();
	virtual void execute_set_input(int inputnum, int state);
	virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 2 - 1) / 2; }
	virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 2); }

	// device_memory_interface overrides
	virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const { return (spacenum == AS_PROGRAM) ? &m_program_config : ( (spacenum == AS_IO) ? &m_io_config : NULL ); }

	// device_state_interface overrides
	void state_string_export(const device_state_entry &entry, astring &string);
	void state_export(const device_state_entry &entry);
	void state_import(const device_state_entry &entry);

	// device_disasm_interface overrides
	virtual UINT32 disasm_min_opcode_bytes() const { return 1; }
	virtual UINT32 disasm_max_opcode_bytes() const { return 3; }
	virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);

private:
	address_space_config m_program_config;
	address_space_config m_io_config;

	devcb_write8       m_out_status_func;
	devcb_write_line   m_out_inte_func;
	devcb_read_line    m_in_sid_func;
	devcb_write_line   m_out_sod_func;

	int                 m_cputype;        /* 0 8080, 1 8085A */
	PAIR                m_PC,m_SP,m_AF,m_BC,m_DE,m_HL,m_WZ;
	UINT8               m_HALT;
	UINT8               m_IM;             /* interrupt mask (8085A only) */
	UINT8               m_STATUS;         /* status word */

	UINT8               m_after_ei;       /* post-EI processing; starts at 2, check for ints at 0 */
	UINT8               m_nmi_state;      /* raw NMI line state */
	UINT8               m_irq_state[4];   /* raw IRQ line states */
	UINT8               m_trap_pending;   /* TRAP interrupt latched? */
	UINT8               m_trap_im_copy;   /* copy of IM register when TRAP was taken */
	UINT8               m_sod_state;      /* state of the SOD line */

	UINT8               m_ietemp;         /* import/export temp space */

	address_space *m_program;
	direct_read_data *m_direct;
	address_space *m_io;
	int                 m_icount;

	/* cycles lookup */
	static const UINT8 lut_cycles_8080[256];
	static const UINT8 lut_cycles_8085[256];
	UINT8 lut_cycles[256];
	/* flags lookup */
	UINT8 ZS[256];
	UINT8 ZSP[256];

	void set_sod(int state);
	void set_inte(int state);
	void set_status(UINT8 status);
	UINT8 get_rim_value();
	void break_halt_for_interrupt();
	UINT8 ROP();
	UINT8 ARG();
	UINT16 ARG16();
	UINT8 RM(UINT32 a);
	void WM(UINT32 a, UINT8 v);
	void check_for_interrupts();
	void execute_one(int opcode);
	void init_tables();

};


class i8080_cpu_device : public i8085a_cpu_device
{
public:
	// construction/destruction
	i8080_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);

protected:
	virtual UINT32 execute_input_lines() const { return 1; }
	virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return clocks; }
	virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles; }
};


class i8080a_cpu_device : public i8085a_cpu_device
{
public:
	// construction/destruction
	i8080a_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);

protected:
	virtual UINT32 execute_input_lines() const { return 1; }
	virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return clocks; }
	virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return cycles; }
};


extern const device_type I8080;
extern const device_type I8080A;
extern const device_type I8085A;

#endif
