home *** CD-ROM | disk | FTP | other *** search
- /*
- R3000 emu
-
- (C) 1999 BERO
- */
-
- #include "fpse.h"
-
- R3000_REG reg;
-
- // int stop;
-
- void printpc(void)
- {
- PRINTF("%08x:",(int)(PC-4));
- }
-
- void Exception(int cd)
- {
- // if (cd == E_Bp*4) cd = E_Sys*4; // Avoid break exeception
- if (in_slot) {
- EPC=PC-4; CAUSE=cd | 0x80000000;
- } else {
- EPC=PC;
- CAUSE = cd;
- }
- PRINTF("Exception:%x\n",cd);
- // CAUSE = (CAUSE & ~0x3c) | cd;
- SR = (SR & ~0x3f)| ((SR<<2)&0x3f);;
- PC=0x80000080;
- SETPC(PC);
- if (exception_handler()) FPSE_Flags |= STOP;
- SETPC(PC);
- }
-
- /* hwè±Ý */
-
- void Interrupt(void)
- {
- // PRINTF("Interrupt %x\n",PC);
- if (SR&1) { /* èݳêÄé© */
- if (SR & 0x400) { /* wèè±ÝͳêÄé© */
- Exception(0x400);
- }
- }
- }
-
- void Reset(void)
- {
- memset(®,0,sizeof(reg));
- PC = 0xbfc00000;
- /* kernel mode */
- SETPC(PC);
- }
-
- #ifndef INT64
- static void multu(UINT32 v1,UINT32 v2)
- {
- UINT32 v1h,v1l,v2h,v2l;
- UINT32 ll,hl,lh,hh,mid,mid2;
-
- v1l = (UINT16)v1;
- v1h = ((UINT32)v1)>>16;
- v2l = (UINT16)v2;
- v2h = ((UINT32)v2)>>16;
-
- ll = v1l*v2l;
- hl = v1h*v2l;
- lh = v1l*v2h;
- hh = v1h*v2h;
- /*
- |ll|ll|
- |lh|lh|
- |hl|hl|
- |hh|hh|
- --------------
- | mid |
- |carry|
- */
- mid = hl+lh;
- if (mid<hl) hh+=0x10000;
- mid2 = mid + (ll>>16);
- if (mid2<mid) hh+=0x10000;
- rLO = (UINT16)ll|(mid2<<16);
- rHI = hh+(mid>>16);
- }
-
- static void mult(INT32 v1,INT32 v2)
- {
- int sign = (v1^v2)<0;
-
- if (v1<0) {v1 = -v1;}
- if (v2<0) {v2 = -v2;}
- multu(v1,v2);
- if (sign) {
- rLO = -rLO;
- rHI = ~rHI;
- if (rLO==0) rHI++;
- }
- }
- #endif
-
- void bioscheck(int pc)
- {
- switch(pc) {
- case 0xc0:
- case 0xb0:
- case 0xa0:
- if (biosprint(pc)) {
- /* ñT|[g */
- // stop = 1;
- }
- SETPC(PC);
- break;
- }
- }
-
- #define JUMP(pc) { UINT32 newpc=(pc); \
- FPSE_Flags |= IN_SLOT; \
- doInst(); \
- FPSE_Flags &= ~IN_SLOT; \
- PC=newpc; }
-
- #define NOT_IMPREMENT(cd) { printf("not imprement %s: %08x\n",cd,(int)code); \
- FPSE_Flags |= STOP; }
-
- void setpc(int pc)
- {
- PC = pc; SETPC(PC);
- }
-
- #define INSTSIZE (0x280000/4)
- static char flg[INSTSIZE];
- static int nopcounter;
-
- extern int breakpoint;
-
- // #define SUPPORT_HBP
-
- #ifdef SUPPORT_HBP
- #define CHECK_EXECBREAK(adr) \
- if ((CPR0[7] & 0x01000000)==0x01000000) && (adr & CPR0[11])==CPR0[3] ) {\
- /* read break happen */ \
- }
-
- #define CHECK_READBREAK(adr) \
- if ((CPR0[7] & 0x06000000)==0x06000000) && (adr & CPR0[9])==CPR0[5] ) {\
- /* read break happen */ \
- }
-
- #define CHECK_WRITEBREAK(adr) \
- if ((CPR0[7] & 0x0a000000)==0x0a000000) && (adr & CPR0[9])==CPR0[5] ) {\
- /* read break happen */ \
- }
-
- #else
- #define CHECK_EXECBREAK(adr)
- #define CHECK_READBREAK(adr)
- #define CHECK_WRITEBREAK(adr)
- #endif
-
- void doInst(void)
- {
- UINT32 code;
- /*
- if (PC==breakpoint) watch();
- */
- if (stop) return;
-
- CHECK_EXECBREAK(PC);
-
- code = FETCH(PC);
-
- if (disasmflg) {
- UINT32 adr=PC;
- static char strbuf[256];
- if (adr>0xbfc00000) adr = adr-0xbfc00000+0x200000;
- else adr&=0x1fffff;
- if (!flg[adr/4] || debug) {
- flg[adr/4]=1;
- disasm(strbuf,code,PC);
- printf("%08x %08x %s\n",(int)PC,(int)code,strbuf);
- }
- }
- PC+=4;
- /*
- if (reg.r[0]) {
- PRINTF("reg0 boken\n");
- FPSE_Flags |= STOP;
- }
- */
- if (!code) {
- /* nop */
- nopcounter++;
- if (nopcounter>100) {
- FPSE_Flags |= STOP;
- printpc();
- PRINTF("too long nop\n");
- }
- return;
- }
- nopcounter = 0;
-
- switch(code>>26) {
- case SPECIAL:
- switch(code&63) {
- case SLL: rd = (UINT32)rt << ((code>>6)&31); break;
- case SRL: rd = (UINT32)rt >> ((code>>6)&31); break;
- case SRA: rd = (INT32)rt >> ((code>>6)&31); break;
- case SLLV: rd = (UINT32)rt << (rs&31); break;
- case SRLV: rd = (UINT32)rt >> (rs&31); break;
- case SRAV: rd = (INT32)rt >> (rs&31); break;
-
- case ADD:
- #if 1
- rd = rs + rt;
- #else
- {
- int tmp = rs + rt;
- /* ª¯¶ && OÆã̪á¤@*/
- if ((INT32)(rs^rt)>=0 && (INT32)(rs^tmp)<0) {
- EXCEPTION(E_Ovf);
- } else {
- rd = tmp;
- }
- }
- #endif
- break;
- case SUB:
- #if 1
- rd = rs - rt;
- #else
- {
- int tmp = rs - rt;
- /* ªá¤ && OÆã̪á¤@*/
- if ((INT32)(rs^rt)<0 && (INT32)(rs^tmp)<0) {
- EXCEPTION(E_Ovf);
- } else {
- rd = tmp;
- }
- }
- #endif
- break;
- case ADDU: rd = rs + rt; break;
- case SUBU: rd = rs - rt; break;
- case AND: rd = rs & rt; break;
- case OR: rd = rs | rt; break;
- case XOR: rd = rs ^ rt; break;
- case NOR: rd = ~(rs | rt); break;
-
- case SLT: rd = ( (INT32)rs < (INT32) rt); break;
- case SLTU: rd = ((UINT32)rs < (UINT32)rt); break;
-
- case DIV: if (rt) {
- rLO = ( INT32)rs/( INT32)rt;
- rHI=( INT32)rs%( INT32)rt;
- }
- break;
- case DIVU: if (rt) {
- rLO = (UINT32)rs/(UINT32)rt;
- rHI=(UINT32)rs%(UINT32)rt;
- }
- break;
- #ifdef INT64
- case MULT:
- rLO = ((INT64)(INT32)rs*(INT32)rt);
- rHI = ((INT64)(INT32)rs*(INT32)rt)>>32;
- break;
- case MULTU:
- rLO = ((INT64)(UINT32)rs*(UINT32)rt);
- rHI = ((INT64)(UINT32)rs*(UINT32)rt)>>32;
- break;
- #else
- case MULT: mult(rs,rt); break;
- case MULTU: multu(rs,rt); break;
- #endif
-
- case MFHI: rd = rHI; break;
- case MFLO: rd = rLO; break;
- case MTHI: rHI = rs; break;
- case MTLO: rLO = rs; break;
-
- case JALR: rd = PC+4; // reg.r[31] = PC+4;
- case JR: JUMP(rs); SETPC(PC); bioscheck(PC); break;
-
- case BREAK: EXCEPTION(E_Bp); break;
- case SYSCALL:
- PRINTF("syscall: %08x",(int)(reg.r[4]));
- switch(reg.r[4]) {
- case 0:PRINTF("Exception\n"); break;
- case 1:PRINTF("EnterCriticalSection\n"); break;
- case 2:PRINTF("ExitCriticalSection\n"); break;
- default:PRINTF("%d\n",(int)(reg.r[4]));
- }
- EXCEPTION(E_Sys);
- break;
- default: NOT_IMPREMENT("special"); break;
- }
- break;
-
- case BCOND:
- switch(rtno){
- case BLTZAL:reg.r[31]=PC+4;
- case BLTZ: if ((INT32)rs< 0) { JUMP(PC + immS*4); } break;
- case BGEZAL:reg.r[31]=PC+4;
- case BGEZ: if ((INT32)rs>=0) { JUMP(PC + immS*4); } break;
- default: NOT_IMPREMENT("bcond"); break;
- }
- break;
-
- /* BRANCH/JUMP */
- case JAL: reg.r[31] = PC+4;
- case J: JUMP((PC&0xf0000000)|((code&0x03ffffff)<<2)); break;
- case BNE: if (rt!=rs) { JUMP(PC + immS*4); } break;
- case BEQ: if (rt==rs) { JUMP(PC + immS*4); } break;
- case BLEZ: if ((INT32)rs<=0) { JUMP(PC + immS*4); } break;
- case BGTZ: if ((INT32)rs> 0) { JUMP(PC + immS*4); } break;
-
- /* ALU */
- case ADDI:
- #if 1
- rt = rs + immS;
- #else
- {
- int tmp = rs + immS;
- /* ª¯¶ && OÆã̪á¤@*/
- if ((INT32)(rs^immS)>=0 && (INT32)(rs^tmp)<0) {
- EXCEPTION(E_Ovf);
- } else {
- rt = tmp;
- }
- }
- #endif
- break;
- case ADDIU: rt = rs + immS; break;
- case SLTI: rt = ( (INT32)rs < immS); break;
- case SLTIU: rt = ((UINT32)rs < (UINT32)immS); break;
- case ANDI: rt = rs & immU; break;
- case ORI: rt = rs | immU; break;
- case XORI: rt = rs ^ immU; break;
- case LUI: rt = (code<<16); break;
-
- /* COP */
- case COP0:
- switch(rsno) {
- case MFC: rt = CPR0[rdno]; /*PRINTF("cop0:r %d\n",rdno);*/ break;
- case CFC: rt = CCR0[rdno]; PRINTF("cop0:\n"); break;
- case MTC: if (rdno!=13 && rdno!=14) CPR0[rdno] = rt;
- PRINTF("cop0:w %d,%x\n",(int)rdno,(int)rt);
- break;
- case CTC: CCR0[rdno] = rt; /*PRINTF("cop0:\n");*/ break;
- case 16:
- if ((code&31)==16) { /* RFE */
- SR = (SR & ~0xf)| ((SR>>2)&0xf);
- PRINTF("rfe:%x\n",(int)SR);
- break;
- }
- default: NOT_IMPREMENT("COP0"); break;
- }
- break;
- case COP2:
- switch(rsno) {
- case MFC: cop2read(rdno ,CPR2); rt = CPR2[rdno]; break;
- case CFC: cop2read(rdno+32,CPR2); rt = CCR2[rdno]; break;
- case MTC: CPR2[rdno] = rt; cop2write(rdno ,CPR2); break;
- case CTC: CCR2[rdno] = rt; cop2write(rdno+32,CPR2); break;
- default:
- if (cop2(code&0x1ffffff,CPR2))
- FPSE_Flags |= STOP;
- break;
- }
- break;
-
- /* LOAD/STORE */
- case SB:
- CHECK_WRITEBREAK(adr);
- write8(rs+immS,rt); break;
- case SH: {
- UINT32 adr = rs+immS;
- CHECK_WRITEBREAK(adr);
- if (adr&1) { EXCEPTION(E_DBE); }
- else write16(adr,rt);
- }
- break;
- case SW: {
- UINT32 adr = rs+immS;
- CHECK_WRITEBREAK(adr);
- if (adr&3) { EXCEPTION(E_DBE); }
- else write32(adr,rt);
- }
- break;
- case SWL: {
- UINT32 adr = rs + immS;
- UINT32 data;
- CHECK_WRITEBREAK(adr);
- data = read32(adr&~3);
- switch(adr&3) {
- case 3: data = rt; break;
- case 2: data = (data & 0xff000000) | (rt>> 8); break;
- case 1: data = (data & 0xffff0000) | (rt>>16); break;
- case 0: data = (data & 0xffffff00) | (rt>>24); break;
- }
- write32(adr&~3,data);
- }
- break;
- case SWR: {
- UINT32 adr = rs + immS;
- UINT32 data;
- CHECK_WRITEBREAK(adr);
- data = read32(adr&~3);
- switch(adr&3) {
- case 3: data = (data & 0x00ffffff) | (rt<<24); break;
- case 2: data = (data & 0x0000ffff) | (rt<<16); break;
- case 1: data = (data & 0x000000ff) | (rt<< 8); break;
- case 0: data = rt; break;
- }
- write32(adr&~3,data);
- }
- break;
-
- case LB:
- CHECK_READBREAK(rs+immS);
- rt = (INT8)read8(rs+immS); break;
- case LBU:
- CHECK_READBREAK(rs+immS);
- rt = read8(rs+immS); break;
- case LH: {
- UINT32 adr = rs + immS;
- CHECK_READBREAK(rs+immS);
- if (adr&1) { EXCEPTION(E_DBE); }
- else { UINT32 tmp = (INT16)read16(adr); if (rtno) rt=tmp; }
- }
- break;
- case LHU: {
- UINT32 adr = rs + immS;
- CHECK_READBREAK(adr);
- if (adr&1) { EXCEPTION(E_DBE); }
- else { UINT32 tmp = read16(adr); if (rtno) rt=tmp; }
- }
- break;
- case LW: {
- UINT32 adr = rs + immS;
- CHECK_READBREAK(adr);
- if (adr&3) { EXCEPTION(E_DBE); }
- else { UINT32 tmp = read32(adr); if (rtno) rt=tmp; }
- }
- break;
- case LWL: {
- UINT32 adr = rs + immS;
- UINT32 data;
- CHECK_READBREAK(adr);
- data = read32(adr&~3);
- switch(adr&3) {
- case 3: rt = data; break;
- case 2: rt = (rt & 0x000000ff) | (data<< 8); break;
- case 1: rt = (rt & 0x0000ffff) | (data<<16); break;
- case 0: rt = (rt & 0x00ffffff) | (data<<24); break;
- }
- }
- break;
- case LWR: {
- UINT32 adr = rs + immS;
- UINT32 data;
- CHECK_READBREAK(adr);
- data = read32(adr&~3);
- switch(adr&3) {
- case 3: rt = (rt & 0xffffff00) | (data>>24); break;
- case 2: rt = (rt & 0xffff0000) | (data>>16); break;
- case 1: rt = (rt & 0xff000000) | (data>> 8); break;
- case 0: rt = data; break;
- }
- }
- break;
-
- case SWC0: {
- UINT32 adr = rs+immS;
- CHECK_WRITEBREAK(adr);
- if (adr&3) { EXCEPTION(E_DBE); }
- else write32(adr,CPR0[rtno]);
- }
- break;
- case LWC0: {
- UINT32 adr = rs+immS;
- CHECK_READBREAK(adr);
- if (adr&3) { EXCEPTION(E_DBE); }
- else CPR0[rtno] = read32(rs+immS);
- }
- break;
- case SWC2: {
- UINT32 adr = rs+immS;
- CHECK_WRITEBREAK(adr);
- if (adr&3) { EXCEPTION(E_DBE); }
- else { cop2read(rtno,CPR2); write32(adr,CPR2[rtno]); }
- }
- break;
- case LWC2: {
- UINT32 adr = rs+immS;
- CHECK_READBREAK(adr);
- if (adr&3) { EXCEPTION(E_DBE); }
- else { CPR2[rtno] = read32(adr); cop2write(rtno,CPR2); }
- }
- break;
- default: NOT_IMPREMENT("??"); break;
- }
- reg.r[0] = 0;
- }