📄 cp0.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 + -