
#include "emuprocessor.h"
#include "simemu.h"
#include "qjbdisplay.h";

using namespace std;


R32 tagset (R32 a, int b) {

	return (a & AddrMask) + (b & TagMask);

}










void EmuProcessor::PPLUS () {

	push2_ds ( tos2 + tos );

}


void EmuProcessor::PMINUS () {

	push2_ds ( tos2 - tos );

}

void EmuProcessor::PTIMES () {

	push2_ds ( ((tos2>>2) * (tos>>2))<<2 );

}


void EmuProcessor::PLE () {

	push2_ds ( (tos2 <= tos) ? minus_one : regC );
}


void EmuProcessor::PGE () {

	push2_ds ( (tos2 >= tos) ? minus_one : regC );
	
}


void EmuProcessor::PLT () {

	push2_ds ( (tos2 < tos) ? minus_one : regC );

}


void EmuProcessor::PGT () {

	push2_ds ( (tos2 > tos) ? minus_one : regC );

}


void EmuProcessor::PEQ () {

	push2_ds ( (tos2 == tos) ? minus_one : regC );

}


void EmuProcessor::PNE () {

	push2_ds ( (tos2 != tos) ? minus_one : regC );

}




void EmuProcessor::P_ALIGN3 () {

	int x = R2I(tos);
	x = (x & 7) ? ((x & (~7)) + 8) : x;

	push1_ds ( x<<2 );

}


void EmuProcessor::P_CONSTR () {

	push2_ds ( ((tos2 & ((1<<18)-1))<<14) | ((tos & ((1<<18)-1))>>2) );


}


void EmuProcessor::P_ADD () {

	push2_ds ( tos2 + R2I(tos) );

}


void EmuProcessor::P_SHIFTL_1 () {

	push1_ds ( (tos<<1) ); 

}


void EmuProcessor::P_SHIFTR_1 () {

	push1_ds ( (tos>>1)&((1<<31)-1) );
}


void EmuProcessor::P_SHIFTL () {

	push2_ds ( (tos2<<(tos/4)) ); 

}


void EmuProcessor::P_SHIFTR () {

	push2_ds ( (tos2>>(tos/4))&((1<<31)-1) );
}


void EmuProcessor::GET_INFO () {

	push1_ds ( ((R32) instrCnt) );

}

void EmuProcessor::TAG_AND () {

	push2_ds ( (tos2 & AddrMask) | ((TagMask & tos2) & (TagMask & (tos>>2))) );

}


void EmuProcessor::TAG_IOR () {

	push2_ds ( (tos2 & AddrMask) | ((TagMask & tos2) | (TagMask & (tos>>2))) );

}


void EmuProcessor::TAG_XOR () {

	push2_ds ( (tos2 & AddrMask) | ((TagMask & tos2) ^ (TagMask & (tos>>2))) );

}


void EmuProcessor::TAG_EQ () {

	push2_ds ( ((tos2 & TagMask ) == ((tos>>2) & TagMask)) ? minus_one : regC );
}


void EmuProcessor::GET_TAG () {

	push1_ds ( ((tos & TagMask)<<2) );

}


void EmuProcessor::TAG_SET () {

R32 val = tagset (tos2, R2I(tos) );

push2_ds (val);

}




void EmuProcessor::ADDR_EQ () {

	push2_ds ( (tos2 & AddrMask) == (tos & AddrMask) ? minus_one : regC );

}


void EmuProcessor::ADDR_EQI () {

	push2_ds ( (tos2 & AddrMask) == (tos & AddrMask) ? minus_one : regC );

	// addr_eqi is identical with addr_eq, differs from msys-pack.lisp
	// see microprogram.mic and cpu20a.v for authoritative reference
	
}


void EmuProcessor::ADDR_AND () {

	push2_ds ( (tos2 & (tos & AddrMask)) | (tos2 & TagMask) );

	// differs from msys-pack.lisp

}




void EmuProcessor::ADDR_IOR () {

	push2_ds ( tos2 | (tos & AddrMask) );

	// differs from msys-pack.lisp

}


void EmuProcessor::GET_ADDR () {

	push1_ds ( tos & AddrMask );

}





void EmuProcessor::GET_BYTE () {

	R32 total_offset = (tos2 & AddrMask) + R2I(tos);

	char res;

	if ((total_offset & HighMask) == VGASelMask) {

		total_offset &= (~VGASelMask);

		res = getmembyte ( pvgamem, total_offset );

	} else	if ((total_offset & HighMask) == SRAMSelMask) {

		total_offset &= (~SRAMSelMask);

		res = getmembyte ( psrammem, total_offset );

	} else	if ((total_offset & HighMask) == CtrlSelMask) {

		total_offset &= (~CtrlSelMask);

		res = getmembyte ( psrammem, total_offset );

	} else {

		res = getmembyte (pmainmem, total_offset );

	};
	
	if (C2R(res) > 4*255) {

		cerr << "getbyte error: addr = " << total_offset << endl; 

	};

	push2_ds (C2R(res));


}


void EmuProcessor::SET_BYTE () {

	R32 total_offset = (getmemword(pmainmem, dsp + 8) & AddrMask) + R2I(tos2);

	char res;

	if ((total_offset & HighMask) == VGASelMask) {

		total_offset &= (~VGASelMask);

		res = setmembyte (pvgamem, total_offset, R2I(tos) );

		psimemu->getDisplay()->byteWrite ( total_offset, res );


	} else if ((total_offset & HighMask) == SRAMSelMask) {

		total_offset &= (~SRAMSelMask);

		res = setmembyte (psrammem, total_offset, R2I(tos) );

	} else if ((total_offset & HighMask) == CtrlSelMask) {

		total_offset &= (~CtrlSelMask);

		res = setmembyte (psrammem, total_offset, R2I(tos) );

	} else {

		res = setmembyte (pmainmem, total_offset, R2I(tos) );
	
	}

	push3_ds (C2R(res));

}



void EmuProcessor::GET_WORD () {

	R32 total_offset = (tos2 & AddrMask) + R2I(tos);

	R32 res;

	if ((total_offset & HighMask) == VGASelMask) {

		total_offset &= (~VGASelMask);

		res = getmemword ( pvgamem, total_offset );

	} else if ((total_offset & HighMask) == SRAMSelMask) {

		total_offset &= (~SRAMSelMask);

		res = getmemword ( psrammem, total_offset );

	} else if ((total_offset & HighMask) == CtrlSelMask) {

		total_offset &= (~CtrlSelMask);

		if (total_offset == 8) {

			res = irqDispatcher.aktKey;

		} else {

			res = 0	;
		}


	} else {

		res = getmemword (pmainmem, total_offset );

	};

	push2_ds (res);

}


void EmuProcessor::SET_WORD () {

	R32 total_offset = (getmemword(pmainmem, dsp + 8) & AddrMask) + R2I(tos2);

	R32 res;

	if ((total_offset & HighMask) == VGASelMask) {

		total_offset &= (~VGASelMask);

		res = setmemword (pvgamem, total_offset, tos );

		psimemu->getDisplay()->wordWrite ( total_offset, ((int)tos) ); 

	} else if ((total_offset & HighMask) == SRAMSelMask) {

		total_offset &= (~SRAMSelMask);

		res = setmemword (psrammem, total_offset, tos );

	} else if ((total_offset & HighMask) == CtrlSelMask) {

		total_offset &= (~CtrlSelMask);

		res = setmemword (psrammem, total_offset, tos );

	} else {

		res = setmemword (pmainmem, total_offset, tos );
	
	}

	push3_ds (res);

}





void EmuProcessor::GET_HWORD () {
}


void EmuProcessor::SET_HWORD () {
}




void EmuProcessor::GET_STATUS () {


push0_ds ( status );


}


void EmuProcessor::SET_STATUS () {


status = tos;

}



void EmuProcessor::GET_DSP () {

push0_ds (dsp);

}


void EmuProcessor::GET_CSP () {

push0_ds( csp);
}



void EmuProcessor::GET_A_INDEX_PP () {
}


void EmuProcessor::SET_B_INDEX_PP () {
}



void EmuProcessor::SET_A () {

regA = tos;

}


void EmuProcessor::SET_B () {

regB = tos;

}



void EmuProcessor::JNIL () {

if (tos == regC) {
	pc_next = pc + (d*4);
};

tos = tos2;
dsp = dsp + 4;
tos2 = getmemwordA(dsp+4);

// cerr << "JNIL" << endl;

}


void EmuProcessor::JMP () {

pc_next = pc + (d*4);

// cerr << "JMP" << endl;

}




void EmuProcessor::LOD () {

R32 val = getmemwordA (dsp + (d*4) );

dsp = dsp - 4;

tos2 = tos;

tos = setmemwordA ( dsp, val );

// cerr << "LOD" << endl;

}


void EmuProcessor::LODNIL () {

dsp = dsp - 4;

tos2 = tos;

tos = setmemwordA ( dsp, regC );

// cerr << "LODNIL" << endl;

}



void EmuProcessor::STO () {

setmemwordA ( dsp + (d*4), tos );

dsp = dsp + 4;

tos = getmemwordA ( dsp );
tos2 = getmemwordA ( dsp + 4);



// cerr << "STO" << endl;

}


void EmuProcessor::LITIDX () {

tos2 = tos;
dsp = dsp - 4;

tos = getmemwordA (litbase + (d*4));

setmemwordA( dsp, tos );

}




void EmuProcessor::INCSP () {

dsp = dsp + (d*4);

tos = getmemwordA ( dsp );
tos2 = getmemwordA ( dsp + 4 );

// cerr << "INCSP" << endl;

}


void EmuProcessor::DECSP () {
}



void EmuProcessor::HALT () {

// cerr << "HALT" << endl;

}



void EmuProcessor::IRQCALLCLOS () {

statusIrqIn ();

setmemwordA ( dsp, getmemwordA ( 16 ) );

dsp = dsp - 4;

setmemwordA ( dsp, tos );

dsp = dsp - 4;

setmemwordA ( dsp, 8 );

tos2 = tos;
tos = 8;

R32 clos = getmemwordA(dsp + 8) & AddrMask;

push_cs ( tp + 2 );

tp = getmemwordA (clos+8) & AddrMask; //closure-ref 0

litbase = tp + 16;

push_cs ( pc );

pc_next = getmemwordA (tp+4);



}









void EmuProcessor::CALLCLOS () {

tos2 = tos;
dsp = dsp - 4;
tos = setmemwordA(dsp, (d*4));

R32 clos = getmemwordA(dsp + (d*4)) & AddrMask;

push_cs ( tp + 2 );

tp = getmemwordA (clos+8) & AddrMask; //closure-ref 0

litbase = tp + 16;

push_cs ( pc + 4);

pc_next = getmemwordA (tp+4);


// cerr << "CALLCLOS" << endl;

}


void EmuProcessor::CALLCLOSV () {

R32 clos = getmemwordA(dsp + tos) & AddrMask;

push_cs ( tp + 2 );

tp = getmemwordA (clos+8) & AddrMask; //closure-ref 0

litbase = tp + 16;

push_cs ( pc + 4);

pc_next = getmemwordA (tp+4);


// cerr << "CALLCLOSV" << endl;

}


void EmuProcessor::RET () {

if (status & (1<<9))
	statusIrqOut ();

pc_next = pop_cs ();
tp = pop_cs () & AddrMask;

litbase = tp + 16;

// cerr << "RET" << endl;

}




void EmuProcessor::LODCS () {

	push0_ds ( getmemwordA ( csp + (d*4) ) );

}


void EmuProcessor::STOCS () {

	setmemwordA ( csp + (d*4), tos);

	tos = tos2;
	dsp = dsp + 4;
	tos2 = getmemwordA ( dsp + 4 );

}



void EmuProcessor::PUSHCS () {

	R32 val = getmemwordA ( dsp + (d*4));

	push_cs (val);



}


void EmuProcessor::INCCSP () {

	csp = csp + (d*4);

}




void EmuProcessor::EXCEPT () {
}



void EmuProcessor::LITIDXSYMFUN () {
}




void EmuProcessor::QPRINT () {

cerr << "::: EMU OUT :" << tos << endl;

}



void EmuProcessor::QSET_SYMBOL_FUNCTION () {

R32 val = setmemwordA((tos2 & AddrMask) + 12, tos);

push2_ds ( val );

// cerr << "SET_SYMBOL_FUNCTION" << endl;

}


void EmuProcessor::QSET_SYMBOL_VALUE () {

R32 val = setmemwordA((tos2 & AddrMask) + 8, tos);

push2_ds ( val );

// cerr << "SET_SYMBOL_VALUE" << endl;
}



void EmuProcessor::QSYMBOL_FUNCTION () {

push1_ds ( getmemwordA((tos & AddrMask) + 12) );

// cerr << "SYMBOL_FUNCTION" << endl;

}


void EmuProcessor::QSYMBOL_VALUE () {

push1_ds ( getmemwordA((tos & AddrMask) + 8) );

// cerr << "SYMBOL_VALUE" << endl;
}



void EmuProcessor::QSVREF () {

push2_ds ( getmemwordA ( (tos2 & AddrMask) + tos + 12 ) );

}


void EmuProcessor::QSET_SVREF () {

R32 tos3 = getmemwordA ( dsp + 8 ) & AddrMask;

push3_ds ( setmemwordA ( tos3 + tos2 + 12, tos ) );

}




void EmuProcessor::QCLOSURE_REF () {

push2_ds (getmemwordA ( (tos2 & AddrMask) + tos + 8 ) );

// cerr << "CLOSURE-REF" << endl;

}



void EmuProcessor::CAR () {

	push1_ds ( getmemwordA ( tos & AddrMask ) );

}


void EmuProcessor::CDR () {
	
	push1_ds ( getmemwordA ( (tos & AddrMask) + 4 ) );

}





