⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cp0.c

📁 一个MIPS虚拟机的源码
💻 C
字号:
#ifdef EXTERN
#undef EXTERN
#endif
#define EXTERN extern

#include "global.h"

static UINT32 cp0_register_mask[CP0_REGISTER_NUMBER]
={CP0_INDEX_MASK,           // 0, INDEX
    CP0_RANDOM_MASK,	 // 1,random
    CP0_ENTRYLO_MASK,     	// 2 ,entrylo
    0,						// 3 entrylo1, mips r4k
    CP0_CONTEXT_MASK,	// 4 context 
    0,						// 5pagemask,mips r4k
    0,						// 6 wired mips r4k
    0,						// 7
    CP0_BADVADDR_MASK,  // 8 bad vaddr
    0,						//9
    CP0_ENTRYHI_MASK,       // 10 entryhi
    0,						 // 11
    CP0_SR_MASK,			 // 12 SR
    CP0_CAUSE_MASK,		 // 13  cause
    0,						 // 14
    CP0_PRID_MASK,              // 15 prid 
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
static char reg_table[CPU_REGISTER_NUMBER][5]=
{
	"zero","at","v0","v1","a0",
	"a1","a2","a3","t0","t1",
	"t2","t3","t4","t5","t6",
	"t7","s0","s1","s2","s3",
	"s4","s5","s6","s7","t8",
	"t9","k0","k1","gp","sp",
	"s8","ra"
};

static char cp0_reg_table[CP0_REGISTER_NUMBER][20]=
{
	"index","random","entrylo","","context",
	"","","","badvaddr","",
	"entryhi","","sr","cause","epc",
	"prid"
};


UINT32 get_ip()
{
	return 0x0000ff00;
}

boolean is_interrupting()
{
	UINT32 interrupt_enable;
	interrupt_enable= cp0_register[SR] & CP0_SR_IEC_MASK;
	if (interrupt_enable!=0x00000001)
		return false;	
	if  ((cp0_register[SR] & CP0_SR_IM_MASK)==0x00000000)
		return false;
	return get_ip();
		
}

void exception(UINT8 exccode,INT8 cp_number)
{
	/*an exception has oocured.*/

	boolean is_delay_slot;
	UINT32 base,vector;
	UINT32 epc,badvaddr;
	
	/**/
	if (exccode==BP)
		{
		halt_machine = true;
		return;
		}
	if (delay_state==DELAYSLOT)
		is_delay_slot = true;
	else
		is_delay_slot = false;
	
	
	
	if (delay_state==DELAYSLOT)
		{
			//an exception occured when executing a delay slot instruction
			epc = PC -4;
		}
	else
		{
			epc = PC;
		}
	

	/* Save exception PC in EPC. */
	cp0_register[EPC] = epc;
	/* Disable interrupts(IEC=0) and Kernel mode(KUC=0 ). */
	cp0_register[SR]  = cp0_register[SR] & ~CP0_SR_IEC_MASK & ~CP0_SR_KUC_MASK;
	/* Clear Cause register BD, CE, and ExcCode fields. */
	cp0_register[CAUSE] &= ~(CP0_CAUSE_BD_MASK| CP0_CAUSE_CE_MASK |CP0_CAUSE_EXCCODE_MASK );
	/* Set Cause register CE field if this is a Coprocessor
	 * Unusable exception.  */
	if (exccode == CPU) {
		cp0_register[CAUSE] |= ((cp_number & 0x00000003) <<28);
	}
	if ((exccode == ADEL) || (exccode==ADES))
		{
			badvaddr = PC;
			cp0_register[BADVADDR]=badvaddr;
		}
	
	/* clear IP field */
	cp0_register[CAUSE] &= ~CP0_CAUSE_IP_MASK;
	/*set BD Field*/
	if (is_delay_slot==true)
		cp0_register[CAUSE]|= 0x80000000;
	else
		cp0_register[CAUSE]&= 0x7fffffff;
	/*set IP AND EXCCODE*/
	cp0_register[CAUSE] |= get_ip () | (exccode << 2);

	/*get base address . determined by SR(BEV) bit*/
	if ((cp0_register[SR] & CP0_SR_BEV_MASK)==CP0_SR_BEV_MASK)
		{
			base = 0xbfc00100;
		}
	else
		{base = 0x80000000;}
	if ( ((exccode==TLBL) || (exccode == TLBS)) && (tlb_miss_type==USER))
		vector = 0x000;
	else
		vector = 0x080;
	
	PC = base + vector;
	exception_padding = true;



	
	
	
}


boolean is_kernel_mode()
{
	//SR(KUC=0):kernel mode
	
	if ((cp0_register[SR] & CP0_SR_KUC_MASK)== 0)
		return true;
	else 
		return false;
	
}

int memory_region(UINT32 vaddr)
{
	switch (vaddr & 0xe0000000)
		{
		
		case 0x80000000:
			return KSEG0;
		case 0xa0000000:
			return KSEG1;
		case 0xc0000000:
		case 0xe0000000:
			return KSEG2;
		default:
			return KUSEG;
		}
}


/* find the match TLB entry. return -1  if failed. return index if successed.*/
int tlb_lookup(UINT32 vpn,UINT32 asid)
{
	int i;
	UINT32 tlb_vpn;
	UINT32 tlb_asid;
	UINT32 tlb_global;
	//printf("vpn  %x\n",vpn);
	//printf("asid  %x\n",asid);
	
	for (i=0;i<TLBENTRY_NO;i++)
		{
			tlb_global = tlb[i].entrylo & CP0_ENTRYLO_G_MASK;
			tlb_vpn= tlb[i].entryhi & CP0_ENTRYHI_VPN_MASK;
			tlb_asid=tlb[i].entryhi & CP0_ENTRYHI_ASID_MASK;
			if (i==63)
				{
					//printf("tlb_vpn\n",tlb_vpn);
					//printf("tlb_asid\n",tlb_asid);
				}
			if ((vpn==tlb_vpn) &&(tlb_global ||(tlb_asid==tlb_asid)  ))
				return i;
			
		}
	if (i==TLBENTRY_NO)
		return -1;
	
}


/* return the phyaddr. if exctiption, return 0xffffffff */
UINT32  tlb_translate_address(UINT32 vaddr, int operation_mode,boolean * cache_able)
{
	UINT32 vpn;
	UINT32 asid;
	int index;
	//int i;
	
	vpn = vaddr & CP0_ENTRYHI_VPN_MASK;
	//asid = cp0_register[ENTRYHI] & CP0_ENTRYHI_ASID_MASK;
	asid =  vaddr & CP0_ENTRYHI_ASID_MASK;
	index = tlb_lookup(vpn,asid);
//	printf("index %x\n",index);
	//printf("cache able %d\n",*cache_able);
	//printf("(tlb[i].entrylo & CP0_ENTRYLO_V_MASK) %x",(tlb[i].entrylo & CP0_ENTRYLO_V_MASK));
	if ((index!=-1) && (tlb[index].entrylo & CP0_ENTRYLO_V_MASK))
		{
			//match & valid
			//printf("222 %d\n",222);
			/*TLB mode exception*/
			if ((operation_mode== DATA_STORE)&& (!(tlb[index].entrylo & CP0_ENTRYLO_D_MASK)) )
				{
					//TLB MODE exception
					exception(MOD,-1);
					return 0xffffffff;
				}
			else
				{
					//printf("111 %d\n",111);
					/*N:0  enable cache. 1:disable cache*/
					if (tlb[index].entrylo & CP0_ENTRYLO_N_MASK)
						*cache_able = false;
					else
						*cache_able = true;
					//printf("cache able %d\n",*cache_able);
					return  ((tlb[index].entrylo & CP0_ENTRYLO_PFN_MASK) | (vaddr & ~CP0_ENTRYHI_VPN_MASK));
				}
		}
	/*not match or V=0*/
	//printf("333 %d\n",333);
	if ((index==-1) ||  (!(tlb[index].entrylo & CP0_ENTRYLO_V_MASK)))
		{
			//no match exception
			if (is_kernel_mode())
				tlb_miss_type = KERNEL;
			else
				tlb_miss_type =USER;
			//set the context and badvaddr register
			cp0_register[BADVADDR] = vaddr;
			cp0_register[CONTEXT]= 0x001ffffc & (((vaddr & 0xfffff000)<<1)>>11);
			if ((operation_mode==DATA_LOAD)||(operation_mode==INSTRUCTION_LOAD))
				{
				exception(TLBL,-1);
				}
			else
				exception(TLBS,-1);
			
			return 0xffffffff;
		}
	
	
	
}


/* translate vaddr to phyaddr.
return the phyaddr.*/
UINT32 vaddr2phyaddr(UINT32 vaddr,int operation_mode,boolean * cache_able )
{
	//fprintf(stderr,"start vaddr2phyaddr()----------------------------------!\n");
	//if ((vaddr % 4)!=0)
	//	{
	//		fprintf(stderr,"vaddr % 4- !=0---------------------------------!\n");
	//bad address exctiption
	//		if ((operation_mode==DATA_LOAD)||(operation_mode==INSTRUCTION_LOAD))
	//			exception(ADEL,-1);
	//		else
	//			exception(ADES,-1);
	//		return 0xffffffff;
	//		
	//	}
	if (!is_kernel_mode() )
		{
		
			/*user mode*/
			if (memory_region(vaddr)!=KUSEG)
				{	// execption. bad address
					if ((operation_mode==DATA_LOAD)||(operation_mode==INSTRUCTION_LOAD))
						exception(ADEL,-1);
					else
						exception(ADES,-1);
					return 0xffffffff;
				}
			else
				{
					return tlb_translate_address(vaddr,operation_mode,cache_able);
				}
		}
	else
		{
			//kernel mode
		//	printf("memory_region %x\n",memory_region(vaddr));
			switch (memory_region(vaddr))
				{
					case KSEG0:
						*cache_able = true;
						return vaddr-KSEG0_V2P_CONST;
					case KSEG1:
						*cache_able = false;
						return vaddr-KSEG1_V2P_CONST;
					case KSEG2:
						/* Whether cache_able is determined by TLB_ENTRY_LO.N*/
						return tlb_translate_address( vaddr,operation_mode,cache_able);
					default:
						/* Whether cache_able is determined by TLB_ENTRY_LO.N*/
						return tlb_translate_address(vaddr,operation_mode,cache_able);
						
				}
		}
	
	
}

boolean is_swc()
{
	if  (cp0_register[SR] & CP0_SR_SWC_MASK)
		return true;
	else 
		return false;
}

boolean is_isc()
{
	if  (cp0_register[SR] & CP0_SR_ISC_MASK)
		return true;
	else 
		return false;
}

static UINT16 get_cs(const UINT32 instruction)
{
	return (instruction >> 11 ) & 0x0000001f;
}
static UINT16 get_cd(const UINT32 instruction)
{
	return (instruction >> 11 ) & 0x0000001f;
}
static UINT16 get_rt(const UINT32 instruction)
{
	return (instruction >> 16 ) & 0x0000001f;
}

/* opcode = 16   mfc0 t,cs*/
void mfc0_simulate(const UINT32 instruction)
{
	
	UINT16 rt,cs;
	rt= get_rt(instruction);
	cs = get_cs(instruction);
	if ((options.debug_mode==true) && (debug.current_mode==STEP))
		printf("%s %s,%s","mfc0",reg_table[get_rt(instruction)],cp0_reg_table[cs]);
	
	cpu_register[rt] = cp0_register[cs] & cp0_register_mask[cs];
}
/* opcode = 16  mtc0  t,cs*/
void mtc0_simulate(const UINT32 instruction)
{
	UINT16 rt,cs;
	rt= get_rt(instruction);
	cs = get_cs(instruction);
	if ((options.debug_mode==true) && (debug.current_mode==STEP))
		printf("%s %s,%s","mtc0",reg_table[get_rt(instruction)],cp0_reg_table[cs]);
	cp0_register[cs] = cpu_register[rt] & cp0_register_mask[cs]  ;
}

/* opcode = 16  tlbr*/
void tlbr_simulate(const UINT32 instruction)
{
 	UINT16 index;
 	if ((options.debug_mode==true) && (debug.current_mode==STEP))
		printf("%s","tlbr");
 	index = (cp0_register[INDEX] & CP0_INDEX_INDEX_MASK)>>8 ;
	cp0_register[ENTRYHI]=tlb[index].entryhi  &  cp0_register_mask[ENTRYHI] ;
	cp0_register[ENTRYLO]=tlb[index].entrylo & cp0_register_mask[ENTRYLO] ;
	
}
/* opcode = 16  tlbwi */
void tlbwi_simulate(const UINT32 instruction)
{
	UINT16 index;
	if ((options.debug_mode==true) && (debug.current_mode==STEP))
		printf("%s","tlbwi");
 	index = (cp0_register[INDEX] & CP0_INDEX_INDEX_MASK)>>8 ;
 	tlb[index].entryhi = cp0_register[ENTRYHI]   &  cp0_register_mask[ENTRYHI] ;
 	tlb[index].entrylo = cp0_register[ENTRYLO]   &  cp0_register_mask[ENTRYLO] ;
}

/* opcode=16  tlbwr */
void tlbwr_simulate(const UINT32 instruction)
{
	UINT16 index;
	if ((options.debug_mode==true) && (debug.current_mode==STEP))
		printf("%s","tlbwr");
 	index = (cp0_register[RANDOM] & CP0_RANDOM_RANDOM_MASK)>>8 ;
 	tlb[index].entryhi = cp0_register[ENTRYHI]   &  cp0_register_mask[ENTRYHI] ;
 	tlb[index].entrylo = cp0_register[ENTRYLO]   &  cp0_register_mask[ENTRYLO] ;
}
/* opcode=16  tlbp */
void tlbp_simulate(const UINT32 instruction)
{
	UINT32 vpn,asid;
	int index;
	if ((options.debug_mode==true) && (debug.current_mode==STEP))
		printf("%s","tlbp");
	vpn = cp0_register[ENTRYHI] & CP0_ENTRYHI_VPN_MASK;
	asid = cp0_register[ENTRYHI] & CP0_ENTRYHI_ASID_MASK;
	index = tlb_lookup(vpn,asid);
	if (index == -1)
		{
			cp0_register[INDEX]=0x80000000;
		}
	else
		{
			cp0_register[INDEX]= (index<<8) & CP0_INDEX_INDEX_MASK;
		}

}

/* opcode=16  rfe*/
void rfe_simulate(const UINT32 instruction)
{
	if ((options.debug_mode==true) && (debug.current_mode==STEP))
		printf("%s","rfe");
	cp0_register[SR] = ((cp0_register[SR] >>2) & 0x0000000f) |( cp0_register[SR] & 0xfffffff0 );
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -