/***************************************************************************
 *   Copyright (C) 2008 by Jürgen Böhm   *
 *   juergen.boehm@aviduratas.de   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   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.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef EMUPROCESSOR_H
#define EMUPROCESSOR_H

/**
@author Jürgen Böhm
*/


#include "irqdispatcher.h"


#include <qstring.h>
#include <qapplication.h>

#include <iostream>
#include <new>

typedef int R32;



static R32 LowMask = (1<<16) - 1;
static R32 LUMask = ((1<<8)-1)<<16;
static R32 HUMask = LUMask<<8;

static R32 AddrMask = (((1<<30)-1)<<2);
static R32 TagMask = 3;

static R32 VGASelMask = (15<<28);
static R32 HighMask = VGASelMask;

static R32 SRAMSelMask = (13<<28);

static R32 CtrlSelMask = (14<<28);


R32 tagset (R32 a, int b);


inline int R2I (R32 a) {
	return a/4;
}; 


inline R32 C2R (char c) { return (((R32)((unsigned char)c))<<2); }

class simemu;


class EmuProcessor{

public:

	    EmuProcessor(simemu* apsimemu) : psimemu( apsimemu) {

			haltFlag = false;
			breakFlag = false;

			instrCnt = 0;
		
			pmainmem = allocateMem ( 1024 * 1024);
			psrammem = allocateMem ( 1024 * 128 );
			pvgamem = allocateMem ( 1024 * 8 * 4);		
			
			// function_table[0] = &EmuProcessor::startupSequence;		

#include "funtable.h"

		};

    ~EmuProcessor();

		typedef void (EmuProcessor::*EMUF) ();



		void toggleHalt () {haltFlag = !haltFlag; };
		void setBreak () {breakFlag = true; };

		char* allocateMem ( int size);

		char setmembyte ( char* p, int addr, int byteval ) {return p[addr] = (char)((unsigned char)byteval);}
		char getmembyte ( char* p, int addr ) { return p[addr]; }

		R32 getmemword ( char* p, int addr );
		R32 setmemword (char *p, int addr, R32 val);

		R32 getmemwordA (int addr );
		R32 setmemwordA (int addr, R32 val);

		R32 setmemwordAdirect (int addr, R32 val);

		char* pgetmainmem () { return pmainmem; }
		char* pgetsrammem () {return psrammem; }
		char* pgetvgamem () {return pvgamem; }


		int irqAccepted (int irq);

		void statusIrqIn ();
		void statusIrqOut ();

		void execute (int adsp, int acsp, int steps);

		int executeInstr (int irq, int wait);

		void startupSequence ();

//#include "fundeclares.h"

void IRQCALLCLOS ();


void PPLUS ();
void PMINUS ();
void PTIMES ();
void PLE ();
void PGE ();
void PLT ();
void PGT ();
void PEQ ();
void PNE ();
void P_ALIGN3 ();
void P_CONSTR ();
void P_ADD ();
void P_SHIFTL_1 ();
void P_SHIFTR_1 ();

void P_SHIFTL ();
void P_SHIFTR ();

void GET_INFO ();
void TAG_AND ();
void TAG_IOR ();
void TAG_XOR ();
void TAG_EQ ();
void GET_TAG ();
void TAG_SET ();
void ADDR_EQ ();
void ADDR_EQI ();
void ADDR_AND ();
void ADDR_IOR ();
void GET_ADDR ();
void GET_BYTE ();
void SET_BYTE ();
void GET_WORD ();
void SET_WORD ();
void GET_HWORD ();
void SET_HWORD ();
void GET_STATUS ();
void SET_STATUS ();
void GET_DSP ();
void GET_CSP ();
void GET_A_INDEX_PP ();
void SET_B_INDEX_PP ();
void SET_A ();
void SET_B ();
void JNIL ();
void JMP ();
void LOD ();
void LODNIL ();
void STO ();
void LITIDX ();
void INCSP ();
void DECSP ();
void HALT ();
void CALLCLOS ();
void CALLCLOSV ();
void RET ();
void LODCS ();
void STOCS ();
void PUSHCS ();
void INCCSP ();
void EXCEPT ();
void LITIDXSYMFUN ();
void QPRINT ();
void QSET_SYMBOL_FUNCTION ();
void QSET_SYMBOL_VALUE ();
void QSYMBOL_FUNCTION ();
void QSYMBOL_VALUE ();
void QSVREF ();
void QSET_SVREF ();
void QCLOSURE_REF ();
void CAR ();
void CDR ();


		R32 pop_cs();
		void push_cs (R32 val);


		void push0_ds ( R32 val );
		void push1_ds ( R32 val );
		void push2_ds ( R32 val );
		void push3_ds ( R32 val );


		IrqDispatcher irqDispatcher;

		static const R32 minus_one = -1;


		bool haltFlag;
		bool breakFlag;

		int irq_akt;


// debugging vars
	
		R32 tosold;



		simemu* psimemu;


		EMUF function_table[64];

		EMUF opcode_1_table[64];
		EMUF opcode_2_table[128];


		unsigned int instrCnt;


		char *pmainmem;
		char *psrammem;
		char *pvgamem;

		R32 dsp;
		R32 csp;

		R32 regA;
		R32 regB;

		R32 regC;

		R32 regD;
		R32 regE;

		R32 pc;
		
		R32 tp;

		R32 litbase;

		R32 ir;
		R32 il, ih;

		R32 d;

		R32 tos, tos2;

		R32 pc_next;

		R32 status;

		

};

#endif
