#include "pxa255_IC.h"
#include "mem.h"


static void pxa255icPrvHandleChanges(Pxa255ic* ic){

	Boolean nowIrq, nowFiq;
	UInt32 unmasked = ic->ICPR & ic->ICMR;
	
	nowFiq = (unmasked & ic->ICLR) != 0;
	nowIrq = (unmasked & ~ic->ICLR) != 0;
	
	if(nowFiq != ic->wasFiq) cpuIrq(ic->cpu, true, nowFiq);
	if(nowIrq != ic->wasIrq) cpuIrq(ic->cpu, false, nowIrq);

	ic->wasFiq = nowFiq;
	ic->wasIrq = nowIrq;
}

static Boolean pxa255icPrvMemAccessF(void* userData, UInt32 pa, UInt8 size, Boolean write, void* buf){
	
	Pxa255ic* ic = userData;
	UInt32 val = 0;
	
	if(size != 4) {
		err_str(__FILE__ ": Unexpected ");
	//	err_str(write ? "write" : "read");
	//	err_str(" of ");
	//	err_dec(size);
	//	err_str(" bytes to 0x");
	//	err_hex(pa);
	//	err_str("\r\n");
		return true;		//we do not support non-word accesses
	}
	
	pa = (pa - PXA255_IC_BASE) >> 2;
	
	if(write){
		if(pa == 1) ic->ICMR = *(UInt32*)buf;
		else if(pa == 2) ic->ICLR = *(UInt32*)buf;
		else if(pa == 5) ic->ICCR = *(UInt32*)buf;
		else return true;
		pxa255icPrvHandleChanges(ic);
	}
	else{
		switch(pa){
			
			case 0:
				val = ic->ICPR & ic->ICMR & ~ic->ICLR;
				break;
			
			case 1:
				val = ic->ICMR;
				break;
			
			case 2:
				val = ic->ICLR;
				break;
			
			case 3:
				val = ic->ICPR & ic->ICMR & ic->ICLR;
				break;
			
			case 4:
				val = ic->ICPR;
				break;
			
			case 5:
				val = ic->ICCR;
				break;
			
		}
		*(UInt32*)buf = val;
	}
	return true;
}

Boolean pxa255icInit(Pxa255ic* ic, ArmCpu* cpu, ArmMem* physMem){
	
	__mem_zero(ic, sizeof(Pxa255ic));
	ic->cpu = cpu;
	return memRegionAdd(physMem, PXA255_IC_BASE, PXA255_IC_SIZE, pxa255icPrvMemAccessF, ic);
}


void pxa255icInt(Pxa255ic* ic, UInt8 intNum, Boolean raise){		//interrupt caused by emulated hardware
	
	UInt32 old_, new_;
	
	old_ = new_ = ic->ICPR;
	
	if(raise) new_ |= (1UL << intNum);
	else new_ &=~ (1UL << intNum);
	
	if(new_ != old_){
		ic->ICPR = new_;
		pxa255icPrvHandleChanges(ic);
	}
}





