/*	Copyright  (c)	Günter Woigk 2013 - 2013
					mailto:kio@little-bat.de

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

	Permission to use, copy, modify, distribute, and sell this software and
	its documentation for any purpose is hereby granted without fee, provided
	that the above copyright notice appear in all copies and that both that
	copyright notice and this permission notice appear in supporting
	documentation, and that the name of the copyright holder not be used
	in advertising or publicity pertaining to distribution of the software
	without specific, written prior permission.  The copyright holder makes no
	representations about the suitability of this software for any purpose.
	It is provided "as is" without express or implied warranty.

	THE COPYRIGHT HOLDER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
	INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
	EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR
	CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
	DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
	TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
	PERFORMANCE OF THIS SOFTWARE.
*/




#ifndef CPU_H
#define CPU_H


#include "kio/kio.h"
#include <QObject>
#include "Templates/Array.h"


extern uint verbose;
extern uint debug;
extern int warnings;

extern class Cpu* cpu;
extern class Sio* sio;
extern class Inspector* cpu_inspector;
extern class Inspector* sio_inspector;
extern class Inspector* memory_inspector;
extern class Inspector* microcode_inspector;
extern cstr QEventTypeStr(int /*QEvent::Type*/ n);


#define floating_k1_bus 0x0000
#define floating_dbus	0xFF00
#define floating_abus	0xFF00

#define SIO_ID	2	// device id: 1 .. 14

class Device;
class Sio;
typedef double Frequency;
typedef double Time;


union Byte
{
	uint32 corebyte;
#ifdef __BIG_ENDIAN__
	struct { uint16 bits, data; };	// bits im high word, ramdata im low word
#endif
#ifdef __LITTLE_ENDIAN__
	struct { uint16 data, bits; };	// bits im high word, ramdata im low word
#endif
};

#define cpu_break_x		0x0001
#define cpu_break_w		0x0002
#define cpu_break_r		0x0004
#define cpu_break_rwx	0x0007	// for convenience



/*	Bits in div.FF:
 */
enum DivFF
{
	div_clk2 = 0,
	div_clk4,
	div_halt,
	div_ei,
	led_grn,
	led_yel,
	led_red,
	div_reset
};




class Cpu : public QObject
{
	Q_OBJECT

friend class CpuInspector;
friend class MicrocodeInspector;
friend class MemoryInspector;
friend class MemoryHexInspector;

	Frequency	xtal;

	uint8	div_ff;

	uint16	areg_ip;
	uint16	areg_sp;
	uint16	areg_a0;
	uint16	areg_a1;
	uint16	areg_hp;
	uint16	areg_atmp;
	uint16	areg_ioaddr;

	uint16	dreg_d0;
	uint16	dreg_d1;
	uint16	dreg_d2;
	uint16	dreg_d3;
	uint16	dreg_alu;
	uint16	dreg_swap;
	uint16	dreg_sr;
	uint16	dreg_sl;
	uint16	dreg_msbit;
	uint16	dreg_cmd_lo;
	uint16	reg_d2ar;

	uint16	mca1;				// microcode address in stage 1
	uint16	mca2;				// microcode address in stage 2
	int32	cc;					// current cpu cycle

//	uint32	breakpoint_read;
//	uint32	breakpoint_write;
	uint32	breakpoint_exec;	// Microcode
	uint32	breakpoint_return;

	uint16	k1bus_select_bits;			// set by io.select		complemented => pos. Logik
	uint16	k1bus_irpt_enable_bits;		// set by io.wr_irpt	complemented => pos. Logik
	uint16	k1bus_irpt_pending_bits;	// set by boards 		complemented => pos. Logik

	uint	state;	enum {stopped,running};

	uint	lastlabel,lastlabel2;
	Array<uint16> labelstack;		// monitors debugger hooks 'login' and 'logout'

	pthread_t tid;				// run() thread

	Device*	k1bus_selected_device;
	Device*	k1bus_devices[16];

	Byte	ram[0x10000];		// Ram
	uint32	mc[0x8000];			// Microcode Rom
	cstr	label[0x8000];		// ref from mca to label



	uint16	get_alu_result	(uint32 mc2, uint16 dbus);
	bool	get_alu_cy		(uint32 mc2, uint16 dbus);
	uint16	get_alu_ovfl	(uint32 mc2, uint16 dbus);

	void	log_registers	();
	void	log_labelstack	();
	void	log_mem			();
	void	log_z			(uint32 mc2, uint16 dbus);
	void	log_cy			(uint32 mc2, uint16 dbus);
	int		wait			(int);


public:
			Cpu();
			~Cpu();

	void	init			(cstr microcodefile, cstr labelsfile, cstr sio_eepromfile);
	void	run				(uint32 cc_end, bool stop_on_breakpoints);
	void	run				();

	Sio*	getSio			()					{ return sio; }
	uint	toggle_state	()					{ return state = !state; }
	void	set_state		(uint b)			{ state = b; }
	bool	is_running		()					{ return state==running; }
	bool	is_stopped		()					{ return state==stopped; }

// K1-Bus:
	bool	k1bus_is_irpt	()					{ return (k1bus_irpt_enable_bits & k1bus_irpt_pending_bits) != 0; }
	bool	k1bus_no_irpt	()					{ return (k1bus_irpt_enable_bits & k1bus_irpt_pending_bits) == 0; }
	void	k1bus_set_irpt	(uint16 pmask, bool flag);		// callback from boards

signals:

public slots:

};



#endif // CPU_H






















