/* * dlx.c * $Id: dlx.c,v 1.40 2005/01/28 16:12:45 obi Exp $ * Christoph Berg * Mark Hillebrand */ // TODO check for resetting doorbell while its active (at the moment impossible) // TODO outputs of most operations is wrong if some source register = destination register #include #include #include "dlx.h" #include "hex.h" #include "math.h" #include "memory.h" #include "opcode.h" #include "trap.h" struct state_s state; struct prof_s prof; char* spr_name1[]= { "SR", "ESR", "ECA", "EPC", "EDPC", "EDATA", "RM", "IEEEf", "FCC" }; #define SPR_SIZE1 (9) char* spr_name2[]= { "SR", "ESR", "ECA", "EPC", "EDPC", "EDATA", "RM", "IEEEf", "FCC", "PTO", "PTL", "EMODE", "FRE1", "FRE2", "FRE3", "FRE4", "MODE" }; #define SPR_SIZE2 (17) char** spr_name = spr_name1; int SPR_SIZE = SPR_SIZE1; char* cause_name[CA_SIZE]= {"reset", "ill", "mal", "ipf", "dpf", "trap", "ovf", "FPUovf", "FPUunf", "FPUinx", "FPUdiv0", "FPUinv", "FPUunimpl", "ex[1]", "ex[2]", "ex[3]", "ex[4]", "ex[5]", "ex[6]", "ex[7]", "ex[8]", "ex[9]", "ex[10]", "ex[11]", "ex[12]", "ex[13]", "ex[14]", "ex[15]", "ex[16]", "ex[17]", "ex[18]", "ex[19]" }; int arch = 0; int ticks = -1; int tcount = -1; void init_timer(int t) { ticks = tcount = t; } void init_arch(int a) { if( a & ARCH_VM ) { spr_name = spr_name2; SPR_SIZE = SPR_SIZE2; } arch = a; // without VM is default, nothing to do here } void exrequest(int index) { int mask = 1< 0) printf("Timer state: %d of %d instruction(s) left until next interrupt\n\n", tcount, ticks); printf("(use 'fpr' to view the FPR contents)\n"); } void init_prof() { bzero(&prof, sizeof(struct prof_s)); } void print_prof() { printf("profile:\n"); printf("%d instr, ", prof.instr); printf("%d nop, %d inv, %d inv_r\n", prof.nop, prof.inv, prof.inv_r); printf("%d j, %d jal, %d trap, %d rfe\n", prof.j, prof.jal, prof.trap, prof.rfe); printf("%d lb, %d lh, %d lw, %d lbu, %d lhu, %d sb, %d sh, %d sw\n", prof.lb, prof.lh, prof.lw, prof.lbu, prof.lhu, prof.sb, prof.sh, prof.sw); printf("%d addio, %d addi, %d subio, %d subi\n", prof.addio, prof.addi, prof.subio, prof.subi); printf("%d andi, %d ori, %d xori, %d lhgi\n", prof.andi, prof.ori, prof.xori, prof.lhgi); printf("%d clri, %d sgri, %d seqi, %d sgei, %d slsi, %d snei, %d slei, %d seti\n", prof.clri, prof.sgri, prof.seqi, prof.sgei, prof.slsi, prof.snei, prof.slei, prof.seti); printf("%d beqz (%d taken), %d bnez (%d taken), %d jr, %d jalr\n", prof.beqz, prof.beqz_taken, prof.bnez, prof.bnez_taken, prof.jr, prof.jalr); printf("%d slli, %d srli, %d srai, %d sll, %d srl, %d sra\n", prof.slli, prof.srli, prof.srai, prof.sll, prof.srl, prof.sra); printf("%d addo, %d add, %d subo, %d sub, %d and, %d or, %d xor, %d lhg\n", prof.addo, prof.add, prof.subo, prof.sub, prof.and, prof.or, prof.xor, prof.lhg); printf("%d clr, %d sgr, %d seq, %d sge, %d sls, %d sne, %d sle, %d set\n", prof.clr, prof.sgr, prof.seq, prof.sge, prof.sls, prof.sne, prof.sle, prof.set); printf("%d movs2i, %d movi2s\n", prof.movs2i, prof.movi2s); } int ovf_add(int a, int b) { /* this follows a proven PVS theorem */ int sum = a + b; return ((a&0x80000000)==(b&0x80000000))&&((a&0x80000000)!=(sum&0x80000000)); } int ovf_sub(int a, int b) { /* should prove a PVS theorem for this :) */ int diff = a - b; return ((a&0x80000000)!=(b&0x80000000))&&((b&0x80000000)==(diff&0x80000000)); } void step_host() { // synchronous host trap handling int doorbell = *((int *)(state.memory + TRAP_MEMLOC)); switch( doorbell ) { case 0: break; // do nothing case 1: dlx_host_trap(); break; default: STEP_WARNING("doorbell has value %s, i.e. neither 0 nor 1", int2str(doorbell) ); // TODO clear doorbell now? } } void step_vamp() { static char c[50]; int *ip, *ip1; double *dp, *dp1, *dp2; float *fp, *fp1, *fp2; int *gpr = state.gpr; int *fpr = state.fpr; int *spr = state.spr; int command; int rs1, rs2, rd_i, rd_r, sa, imm_i, imm_j; int ea; int cfc = 0; // control flow change has default 0 int target; // target of a control flow change int MCA = 0; int fetch = 1; c[0] = '\0'; // default to empty string // instruction fetch prof.instr++; MCA |= memop_fetch(state.dpc,(void*)&command); if(MCA) { // tell exception handling code below // that no instruction was fetched fetch = 0; } else { rs1 = RS1(command); rs2 = RS2(command); rd_i = RD_I(command); rd_r = RD_R(command); sa = SA(command); imm_i = IMM_I(command); imm_j = IMM_J(command); if( state.lastcfi ) { state.stopflag |= STOP_BBEND; state.lastcfi++; } // Note: PC computation is at the end of this function switch(OPCODE(command)) { // J type case OP_J: prof.j++; state.lastcfi++; cfc = 1; target = state.pc + imm_j; STEP_TRACE("j #%d[0x%x]", imm_j, target); break; case OP_JAL: prof.jal++; state.lastcfi++; gpr[LINK_R] = state.pc + 4; cfc = 1; target = state.pc + imm_j; STEP_TRACE("jal #%d[0x%x]", imm_j, target); state.stopflag |= STOP_JAL; break; case OP_TRAP: prof.trap++; MCA |= CA_trap; STEP_TRACE("trap #0x%x", imm_j); break; case OP_RFE: // handled in the PC computation section below! break; // end J // I type case OP_LB: prof.lb++; ea = gpr[rs1]+imm_i; MCA |= memop_load(ea,1,1,(void*)(gpr + rd_i)); // (only bus errors possible here...) STEP_TRACE("lb r%d[%d],%d(r%d)[0x%x]", rd_i, gpr[rd_i], imm_i, rs1, ea); break; case OP_LH: prof.lh++; ea = gpr[rs1]+imm_i; MCA |= memop_load(ea,2,1,(void*)(gpr + rd_i)); STEP_TRACE("lh r%d[%d],%d(r%d)[0x%x]", rd_i, gpr[rd_i], imm_i, rs1, ea); break; case OP_LW: prof.lw++; ea = gpr[rs1]+imm_i; MCA |= memop_load(ea,4,1,(void*)(gpr + rd_i)); STEP_TRACE("lw r%d[%d],%d(r%d)[0x%x]", rd_i, gpr[rd_i], imm_i, rs1, ea); break; case OP_LBU: prof.lbu++; ea = gpr[rs1]+imm_i; MCA |= memop_load(ea,1,0,(void*)(gpr + rd_i)); // (only bus errors possible here...) STEP_TRACE("lbu r%d[%d],%d(r%d)[0x%x]", rd_i, gpr[rd_i], imm_i, rs1, ea); break; case OP_LHU: prof.lhu++; ea = gpr[rs1]+imm_i; MCA |= memop_load(ea,2,0,(void*)(gpr + rd_i)); STEP_TRACE("lhu r%d[%d],%d(r%d)[0x%x]", rd_i, gpr[rd_i], imm_i, rs1, ea); break; case OP_SB: prof.sb++; ea = gpr[rs1]+imm_i; memop_store(ea,1,(void*)(gpr + rd_i) ); // (only bus errors possible here...) STEP_TRACE("sb %d(r%d)[0x%x],r%d[%d]", imm_i, rs1, ea, rd_i, gpr[rd_i]); break; case OP_SH: prof.sh++; ea = gpr[rs1]+imm_i; MCA |= memop_store(ea,2,(void*)(gpr + rd_i) ); STEP_TRACE("sh %d(r%d)[0x%x],r%d[%d]", imm_i, rs1, ea, rd_i, gpr[rd_i]); break; case OP_SW: prof.sw++; ea = gpr[rs1]+imm_i; MCA |= memop_store(ea,4,(void*)(gpr + rd_i) ); STEP_TRACE("sw %d(r%d)[0x%x],r%d[%d]", imm_i, rs1, ea, rd_i, gpr[rd_i]); break; case OP_ADDIO: prof.addio++; gpr[rd_i] = gpr[rs1] + imm_i; if( ovf_add(gpr[rs1],imm_i) ) MCA |= CA_ovf; STEP_TRACE("addio r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_ADDI: prof.addi++; gpr[rd_i] = gpr[rs1] + imm_i; STEP_TRACE("addi r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_SUBIO: prof.subio++; gpr[rd_i] = gpr[rs1] - imm_i; if( ovf_sub(gpr[rs1],imm_i) ) MCA |= CA_ovf; STEP_TRACE("subi r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_SUBI: prof.subi++; gpr[rd_i] = gpr[rs1] - imm_i; STEP_TRACE("subi r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_ANDI: prof.andi++; gpr[rd_i] = gpr[rs1] & imm_i; STEP_TRACE("andi r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_ORI: prof.ori++; gpr[rd_i] = gpr[rs1] | imm_i; STEP_TRACE("ori r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_XORI: prof.xori++; gpr[rd_i] = gpr[rs1] ^ imm_i; STEP_TRACE("xori r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_LHGI: prof.lhgi++; gpr[rd_i] = imm_i << 16; STEP_TRACE("lhgi r%d[0x%x],#%d", rd_i, gpr[rd_i], imm_i); break; case OP_CLRI: prof.clri++; gpr[rd_i] = 0; STEP_TRACE("clri r%d[0]", rd_i); break; case OP_SGRI: prof.sgri++; gpr[rd_i] = gpr[rs1] > imm_i; STEP_TRACE("sgri r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_SEQI: prof.seqi++; gpr[rd_i] = gpr[rs1] == imm_i; STEP_TRACE("seqi r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_SGEI: prof.sgei++; gpr[rd_i] = gpr[rs1] >= imm_i; STEP_TRACE("sgei r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_SLSI: prof.slsi++; gpr[rd_i] = gpr[rs1] < imm_i; STEP_TRACE("slsi r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_SNEI: prof.snei++; gpr[rd_i] = gpr[rs1] != imm_i; STEP_TRACE("snei r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_SLEI: prof.slei++; gpr[rd_i] = gpr[rs1] <= imm_i; STEP_TRACE("slei r%d[%d],r%d[%d],#%d", rd_i, gpr[rd_i], rs1, gpr[rs1], imm_i); break; case OP_SETI: prof.seti++; gpr[rd_i] = 1; STEP_TRACE("seti r%d[1]", rd_i); break; case OP_BEQZ: prof.beqz++; state.lastcfi++; if(gpr[rs1] == 0) { cfc = 1; target = state.pc + imm_i; prof.beqz_taken++; } STEP_TRACE("beqz r%d[%d],#%d", rs1, gpr[rs1], imm_i); break; case OP_BNEZ: prof.bnez++; state.lastcfi++; if(gpr[rs1] != 0) { cfc = 1; target = state.pc + imm_i; prof.bnez_taken++; } STEP_TRACE("bnez r%d[%d],#%d", rs1, gpr[rs1], imm_i); break; case OP_JR: prof.jr++; state.lastcfi++; cfc = 1; target = gpr[rs1]; STEP_TRACE("jr r%d[0x%x]", rs1, target); if (rs1==31) { state.stopflag |= STOP_JR31; } break; case OP_JALR: prof.jalr++; state.lastcfi++; gpr[LINK_R] = state.pc + 4; cfc = 1; target = gpr[rs1]; STEP_TRACE("jalr r%d[0x%x]", rs1, target); break; // end I // FI type case OP_LOAD_S: ea = gpr[rs1]+imm_i; MCA |= memop_load(ea,4,0,(void*)(fpr + rd_i)); STEP_TRACE("load.s fr%d[%f],%d(r%d)[0x%x]",rd_i, *((float*)(fpr + rd_i)), imm_i, rs1, ea); break; case OP_LOAD_D: ea = gpr[rs1]+imm_i; MCA |= memop_load(ea,8,0,(void*)(fpr + rd_i)); STEP_TRACE("load.d fr%d[%G],%d(r%d)[0x%x]",rd_i, *((double*)(fpr + rd_i)), imm_i, rs1, ea); break; case OP_STORE_S: ea = gpr[rs1]+imm_i; MCA |= memop_store(ea,4,(void*)(fpr + rd_i) ); STEP_TRACE("store.s %d(r%d)[0x%x],fr%d[%f]", imm_i, rs1, ea, rd_i, *((float*) (fpr + rd_i)) ); break; case OP_STORE_D: ea = gpr[rs1]+imm_i; MCA |= memop_store(ea,8,(void*)(fpr + rd_i) ); STEP_TRACE("store.d %d(r%d)[0x%x],fr%d[%G]", imm_i, rs1, ea, rd_i, *((double*)(fpr + rd_i)) ); break; case OP_FBEQZ: state.lastcfi++; if(spr[SPR_FCC] == 0) { cfc = 1; target = state.pc + imm_i; } STEP_TRACE("fbeqz #%d (FCC==%d)", imm_i, spr[SPR_FCC]); break; case OP_FBNEZ: state.lastcfi++; if(spr[SPR_FCC] != 0) { cfc = 1; target = state.pc + imm_i; } STEP_TRACE("fbnez #%d (FCC==%d)", imm_i, spr[SPR_FCC]); break; // end FI // R type case OP_R: switch(FUNC(command)) { case R_SLLI: if(command == 0) { prof.nop++; // TODO maybe also check for different nop encodings... } else { prof.slli++; gpr[rd_r] = gpr[rs1] << sa; STEP_TRACE("slli r%d[0x%x],r%d[0x%x],#%d", rd_r, gpr[rd_r], rs1, gpr[rs1], sa); } break; case R_SRLI: prof.srli++; gpr[rd_r] = (unsigned)gpr[rs1] >> sa; STEP_TRACE("srli r%d[0x%x],r%d[0x%x],#%d", rd_r, gpr[rd_r], rs1, gpr[rs1], sa); break; case R_SRAI: prof.srai++; gpr[rd_r] = (signed)gpr[rs1] >> sa; STEP_TRACE("srai r%d[0x%x],r%d[0x%x],#%d", rd_r, gpr[rd_r], rs1, gpr[rs1], sa); break; case R_SLL: prof.sll++; gpr[rd_r] = gpr[rs1] << gpr[rs2 & 0x1f]; STEP_TRACE("sll r%d[0x%x],r%d[0x%x],r%d[0x%x]", rd_r, gpr[rd_r], rs1, gpr[rs1], rs2, gpr[rs2 & 0x1f]); break; STEP_TRACE("sll r%d,r%d,r%d", rd_r, rs1, rs2); break; case R_SRL: prof.srl++; gpr[rd_r] = (unsigned)gpr[rs1] >> gpr[rs2 & 0x1f]; STEP_TRACE("srl r%d[0x%x],r%d[0x%x],r%d[0x%x]", rd_r, gpr[rd_r], rs1, gpr[rs1], rs2, gpr[rs2 & 0x1f]); break; STEP_TRACE("srl r%d,r%d,r%d", rd_r, rs1, rs2); break; case R_SRA: prof.sra++; gpr[rd_r] = (signed)gpr[rs1] >> gpr[rs2 & 0x1f]; STEP_TRACE("sra r%d[0x%x],r%d[0x%x],r%d[0x%x]", rd_r, gpr[rd_r], rs1, gpr[rs1], rs2, gpr[rs2 & 0x1f]); break; case R_ADDO: prof.addo++; gpr[rd_r] = gpr[rs1] + gpr[rs2]; if( ovf_add(gpr[rs1],gpr[rs2]) ) MCA |= CA_ovf; STEP_TRACE("addo r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_ADD: prof.add++; gpr[rd_r] = gpr[rs1] + gpr[rs2]; STEP_TRACE("add r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_SUBO: prof.subo++; gpr[rd_r] = gpr[rs1] - gpr[rs2]; if( ovf_sub(gpr[rs1],gpr[rs2]) ) MCA |= CA_ovf; STEP_TRACE("subo r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_SUB: prof.sub++; gpr[rd_r] = gpr[rs1] - gpr[rs2]; STEP_TRACE("sub r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_AND: prof.and++; gpr[rd_r] = gpr[rs1] & gpr[rs2]; STEP_TRACE("and r%d[0x%x],r%d[0x%x],r%d[0x%x]", rd_r, gpr[rd_r], rs1, gpr[rs1], rs2, gpr[rs2]); break; case R_OR: prof.or++; gpr[rd_r] = gpr[rs1] | gpr[rs2]; STEP_TRACE("or r%d[0x%x],r%d[0x%x],r%d[0x%x]", rd_r, gpr[rd_r], rs1, gpr[rs1], rs2, gpr[rs2]); break; case R_XOR: prof.xor++; gpr[rd_r] = gpr[rs1] ^ gpr[rs2]; STEP_TRACE("xor r%d[0x%x],r%d[0x%x],r%d[0x%x]", rd_r, gpr[rd_r], rs1, gpr[rs1], rs2, gpr[rs2]); break; case R_LHG: prof.lhg++; gpr[rd_r] = gpr[rs2] << 16; STEP_TRACE("lhg r%d[0x%x],r%d[0x%x]", rd_r, gpr[rd_r], rs2, gpr[rs2]); break; case R_CLR: prof.clr++; gpr[rd_r] = 0; STEP_TRACE("clr r%d[0]", rd_r); break; case R_SGR: prof.sgr++; gpr[rd_r] = gpr[rs1] > gpr[rs2]; STEP_TRACE("sgr r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_SEQ: prof.seq++; gpr[rd_r] = gpr[rs1] == gpr[rs2]; STEP_TRACE("seq r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_SGE: prof.sge++; gpr[rd_r] = gpr[rs1] >= gpr[rs2]; STEP_TRACE("sge r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_SLS: prof.sls++; gpr[rd_r] = gpr[rs1] < gpr[rs2]; STEP_TRACE("sls r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_SNE: prof.sne++; gpr[rd_r] = gpr[rs1] != gpr[rs2]; STEP_TRACE("sne r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_SLE: prof.sle++; gpr[rd_r] = gpr[rs1] <= gpr[rs2]; STEP_TRACE("sle r%d[%s],r%d[%s],r%d[%s]", rd_r, int2str(gpr[rd_r]), rs1, int2str(gpr[rs1]), rs2, int2str(gpr[rs2])); break; case R_SET: prof.set++; gpr[rd_r] = 0; STEP_TRACE("set r%d", rd_r); break; case R_MOVS2I: prof.movs2i++; if( arch & ARCH_VM && spr[SPR_MODE]&0x1 && (sa<6 || sa >8) ) MCA |= CA_ill; else gpr[rd_r] = sa8) ) MCA |= CA_ill; else if (sa fpr[rs2]; STEP_TRACE("fc.gt.s fcc[%d],fr%d[%f],fr%d[%f]", spr[SPR_FCC], rs1,*(float *)( fpr + rs1) , rs2,*(float *) (fpr + rs2) ); break; case FMT_D: // double spr[SPR_FCC] = *(double *)(fpr + rs1) > *(double *)(fpr + rs2); STEP_TRACE("fc.gt.d fcc[%d],fr%d[%g],fr%d[%g]", spr[SPR_FCC], rs1, *(double *)(fpr + rs1) , rs2, *(double *)(fpr + rs2)); break; default: STEP_TRACE("Unknown format: FMT? 0x%x", FMT_FR(command)); STEP_TRACE("FR? %08x", command); } break; case FR_LE: // float less equal switch(FMT_FR(command)) { case FMT_S: // single spr[SPR_FCC] = fpr[rs1] <= fpr[rs2]; STEP_TRACE("fc.le.s fcc[%d],fr%d[%f],fr%d[%f]", spr[SPR_FCC], rs1,*(float *)( fpr + rs1) , rs2,*(float *) (fpr + rs2) ); break; case FMT_D: // double spr[SPR_FCC] = *(double *)(fpr + rs1) <= *(double *)(fpr + rs2); STEP_TRACE("fc.le.d fcc[%d],fr%d[%g],fr%d[%g]", spr[SPR_FCC], rs1, *(double *)(fpr + rs1) , rs2, *(double *)(fpr + rs2)); break; default: STEP_TRACE("Unknown format: FMT? 0x%x", FMT_FR(command)); STEP_TRACE("FR? %08x", command); } break; case FR_GE: // float less then switch(FMT_FR(command)) { case FMT_S: // single spr[SPR_FCC] = fpr[rs1] >= fpr[rs2]; STEP_TRACE("fc.ge.s fcc[%d],fr%d[%f],fr%d[%f]", spr[SPR_FCC], rs1,*(float *)( fpr + rs1) , rs2,*(float *) (fpr + rs2) ); break; case FMT_D: // double spr[SPR_FCC] = *(double *)(fpr + rs1) >= *(double *)(fpr + rs2); STEP_TRACE("fc.ge.d fcc[%d],fr%d[%g],fr%d[%g]", spr[SPR_FCC], rs1, *(double *)(fpr + rs1) , rs2, *(double *)(fpr + rs2)); break; default: STEP_TRACE("Unknown format: FMT? 0x%x", FMT_FR(command)); STEP_TRACE("FR? %08x", command); } break; default: STEP_TRACE("Unimplemented: FR? %08x at dpc=0x%x", command,state.dpc); STEP_TRACE("FR? %08x", command); MCA |= CA_ill; } break; // end FR default: prof.inv++; STEP_TRACE("Unimplemented: ?? %08x", command); STEP_TRACE("?? %08x", command); MCA |= CA_ill; } gpr[0] = 0; // invalidate R0 writes if( state.lastcfi & 0x2 ) { if( state.lastcfi & 0x1 ) STEP_WARNING("branch in delay slot at dpc=0x%08x", state.dpc ); state.lastcfi = 0; } } // handle external event linesu // (must set and reset manually with the commands `exrequest' and `exservice' currently) MCA |= state.ex<<12; // PC computation (and interrupt handling) MCA &= spr[SPR_SR] | (CA_reset|CA_ill|CA_mal|CA_ipf|CA_dpf|CA_trap|CA_FPUunimpl); if( MCA ) { // JISR int repeat = MCA & (CA_reset|CA_ill|CA_mal|CA_ipf|CA_dpf); state.stopflag |= STOP_JISR; // notify timer of being serviced // (note: this is deliberately kept a special case, since we are just doing // a quick hack for now) if( state.ex&2 && !(MCA&((1<<13)-1)) ) { exservice(1); } spr[SPR_SR] = 0; spr[SPR_ESR] = repeat ? spr[SPR_SR] : spr[SPR_ESR]; spr[SPR_ECA] = MCA; // Update PCs so that they contain the PC to be saved if( !repeat ) { if( cfc ) { state.dpc = state.pc; state.pc = target; } else { state.dpc = state.pc; state.pc += 4; } } spr[SPR_EPC] = state.pc; spr[SPR_EDPC] = state.dpc; if( !fetch ) spr[SPR_EDATA] = state.dpc; else if( MCA & CA_trap ) spr[SPR_EDATA]=imm_j; else if( MCA & (CA_mal|CA_dpf) ) spr[SPR_EDATA]=ea; else spr[SPR_EDATA] = 0; // TODO missing cases... if( arch & ARCH_VM ) { spr[SPR_EMODE] = spr[SPR_MODE]; spr[SPR_MODE] = 0; state.stopflag |= STOP_CHMOD; state.lastcfi = 0; STEP_TRACE("---JISR, entering system mode---"); // TODO ^ not true when already in system mode } else STEP_TRACE("---JISR---"); state.pc = 4; state.dpc = 0; } else if( OPCODE(command) == OP_RFE ) { // we consider this end of a basic block (maybe we shouldn't, since there is // an RFE event also): state.stopflag |= STOP_RFE; // return from exception prof.rfe++; state.pc =spr[SPR_EPC]; state.dpc=spr[SPR_EDPC]; spr[SPR_SR]=spr[SPR_ESR]; STEP_TRACE("rfe [0x%x]", state.pc); if( arch & ARCH_VM ) { if( (spr[SPR_MODE] = spr[SPR_EMODE])&0x1 ) { STEP_TRACE("---RFE, entering user mode---"); state.stopflag |= STOP_CHMOD; } else STEP_TRACE("---RFE, staying in system mode---"); } else STEP_TRACE("---RFE---"); } else if( cfc ) { // control flow change if(target&0x3) STEP_WARNING("misaligned jump/branch address at dpc=0x%x", state.dpc); if(target == 0) STEP_WARNING("NULL pointer jump/branch at dpc=0x%x", state.dpc); if(target >= state.memorysize) STEP_WARNING("jump/branch to non-allocated memory at address 0x%x", state.dpc); state.dpc = state.pc; state.pc = target; } else { // TODO the warning around here are not really valid for translated mode, right? // inline fetch if( state.pc==(unsigned)-4 ) STEP_WARNING("PC wraps around at dpc=0x%x", state.dpc ); // (can only happen with 4G memory) if( state.pc+4 == state.memorysize ) STEP_WARNING("fetch from non-allocated memory at address 0x%x", state.dpc); state.dpc = state.pc; state.pc += 4; } //return c; } void step_timer() { if( ticks > 0 ) { // timer enabled if( tcount ) { // >0 if( !(--tcount) ) exrequest(1); } else { // ==0 if( !(state.ex&2) ) { // received service, start over tcount = ticks; } } } } void step() { state.stopflag = 0; step_vamp(); step_host(); step_timer(); state.stopflag &= state.stopmask; }