📄 decoder.cc
字号:
#include "instr.hh"#include "koala.hh"// This monster of a switch statement decodes all CPU instructions. I've// decided against an explicit jump table, as such implementation both// increases the code size and introduced additional overhead to the inner// decoder loop.// WARNING: The below code currently does not simulate any slips.// This should be fixed soon (it's fairly easy to simulate, too.)intKoala::decode(Instr instr){ if (catch_nops > 0) { if (instr) nop_count = 0; else if (++nop_count >= catch_nops) { msg("%d NOP instructions executed in a row. Bailing out.", catch_nops); Tcl_Exit(1); } } switch (opcode(instr)) { case SPECIAL: { // Special instructions, decoded using the (function) field. if (trace_level > 4) { dump_state(); } switch (function(instr)) { case SLL: { // Shift Left Logical //////////////////////////////////////////// if (rd(instr)) { // This is optimized for gpr[0], as it comonly used as a NOP. if (trace_level >= print_instructions) log("[%lx]\tsll\t%s, %s, %d", pc, regname[rd(instr)], regname[rt(instr)], shamt(instr)); UInt32 x = gpr[rt(instr)]; int s = shamt(instr); gpr[rd(instr)] = sign_extend<UInt64>(x << s, 32); } else { if (trace_level >= print_instructions) log("[%lx]\tnop", pc); } return nothing_special; } case SRL: { // Shift Right Logical /////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsrl\t%s, %s, %d", pc, regname[rd(instr)], regname[rt(instr)], shamt(instr)); UInt32 x = zero_extend<UInt32>(gpr[rt(instr)], 32); int s = shamt(instr); gpr[rd(instr)] = sign_extend<UInt64>(x >> s, 32); return nothing_special; } case SRA: { // Shift Right Arithmetic //////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsra\t%s, %s, %d", pc, regname[rd(instr)], regname[rt(instr)], shamt(instr)); UInt32 x = zero_extend<UInt32>(gpr[rt(instr)], 32); int s = shamt(instr); gpr[rd(instr)] = sign_extend<UInt64>(x >> s, 32 - s); return nothing_special; } case SLLV: { // Shift Left Logical Variable /////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsllv\t%s, %s, %s", pc, regname[rd(instr)], regname[rt(instr)], regname[rs(instr)]); UInt32 x = gpr[rt(instr)]; int s = bits(gpr[rs(instr)], 4, 0); gpr[rd(instr)] = sign_extend<UInt64>(x << s, 32); return nothing_special; } case SRLV: { // Shift Right Logical Variable ////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsrlv\t%s, %s, %s", pc, regname[rd(instr)], regname[rt(instr)], regname[rs(instr)]); UInt32 x = zero_extend<UInt32>(gpr[rt(instr)], 32); int s = bits(gpr[rs(instr)], 4, 0); gpr[rd(instr)] = sign_extend<UInt64>(x >> s, 32); return nothing_special; } case SRAV: { // Shift Right Arithmetic Variable /////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsrav\t%s, %s, %s", pc, regname[rd(instr)], regname[rt(instr)], regname[rs(instr)]); UInt32 x = gpr[rt(instr)]; int s = bits(gpr[rs(instr)], 4, 0); gpr[rd(instr)] = sign_extend<UInt64>(x >> s, 32 - s); return nothing_special; } case JR: { // Jump Register ///////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tjr\t%s", pc, regname[rs(instr)]); branch_target = gpr[rs(instr)]; if (pipeline == branch_delay) { log("Illegal branch in branch delay slot at: %lx\n", pc); assert(!"Can't handle branch in branch delay slot"); } return bits(branch_target, 1, 0) ? instr_addr_error : branch_delay; } case JALR: { // Jump And Link Register //////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tjalr\t%s, %s", pc, regname[rd(instr)], regname[rs(instr)]); branch_target = gpr[rs(instr)]; gpr[31] = sign_extend<UInt64>(pc + 8, 64); if (pipeline == branch_delay) { log("Illegal branch in branch delay slot at: %lx\n", pc); assert(!"Can't handle branch in branch delay slot"); } return bits(branch_target, 1, 0) ? instr_addr_error : branch_delay; } case SYSCALL: { // System Call /////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsyscall", pc); process_syscall(); return nothing_special; } case BREAK: { // Breakpoint //////////////////////////////////////////////////// if (trace_level >= print_instructions || bits(instr, 31, 16) > 0) log("[%lx]\tbreak\t%d", pc, bits(instr, 31, 16));#if 0 // Enable tracing level. if (trace_level >= 0) { trace_level = bits(instr, 31, 16); if (trace_level == 666) { msg("BREAK 666: bailing out"); Tcl_Exit(1); } msg("Trace level set to %d", trace_level); } else { process_breakpoint(); }#endif process_breakpoint(); return nothing_special; } case SYNC: { // Synchronize /////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsync", pc); sync_bit = true; return nothing_special; } case MFHI: { // Move From HI ////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tmfhi\t%s", pc, regname[rd(instr)]); gpr[rd(instr)] = hi; return nothing_special; } case MTHI: { // Move To HI //////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tmthi\t%s", pc, regname[rs(instr)]); hi = gpr[rs(instr)]; return nothing_special; } case MFLO: { // Move From LO ////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tmflo\t%s", pc, regname[rd(instr)]); gpr[rd(instr)] = lo; return nothing_special; } case MTLO: { // Move To LO //////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tmtlo\t%s", pc, regname[rs(instr)]); lo = gpr[rs(instr)]; return nothing_special; } case DSLLV: { // Doubleword Shift Left Logical Variable //////////////////////// if (trace_level >= print_instructions) log("[%lx]\tdsllv\t%s, %s, %s", pc, regname[rd(instr)], regname[rt(instr)], regname[rs(instr)]); if (!allow_xinstr()) process_reserved_instruction(); UInt64 x = gpr[rt(instr)]; int s = bits(gpr[rs(instr)], 5, 0); gpr[rd(instr)] = sign_extend<UInt64>(x << s, 64); return nothing_special; } case DSRLV: { // Doubleword Shift Right Logical Variable /////////////////////// if (trace_level >= print_instructions) log("[%lx]\tdsrlv\t%s, %s, %s", pc, regname[rd(instr)], regname[rt(instr)], regname[rs(instr)]); if (!allow_xinstr()) process_reserved_instruction(); UInt64 x = zero_extend<UInt64>(gpr[rt(instr)], 64); int s = bits(gpr[rs(instr)], 5, 0); gpr[rd(instr)] = sign_extend<UInt64>(x >> s, 64); return nothing_special; } case DSRAV: { // Doubleword Shift Right Arithmetic Variable //////////////////// if (trace_level >= print_instructions) log("[%lx]\tdsrav\t%s, %s, %s", pc, regname[rd(instr)], regname[rt(instr)], regname[rs(instr)]); if (!allow_xinstr()) process_reserved_instruction(); UInt64 x = gpr[rt(instr)]; int s = bits(gpr[rs(instr)], 5, 0); gpr[rd(instr)] = sign_extend<UInt64>(x >> s, 64 - s); return nothing_special; } case MULT: { // Multiply ////////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tmult\t%s, %s", pc, regname[rs(instr)], regname[rt(instr)]); Int32 x = sign_extend<Int32>(gpr[rs(instr)], 32); Int32 y = sign_extend<Int32>(gpr[rt(instr)], 32); MulResult<Int32> r = multiply(x, y); lo = sign_extend<UInt64>(r.lo, 32); hi = sign_extend<UInt64>(r.hi, 32); return nothing_special; } case MULTU: { // Multiply Unsigned ///////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tmultu\t%s, %s", pc, regname[rs(instr)], regname[rt(instr)]); UInt32 x = zero_extend<UInt32>(gpr[rs(instr)], 32); UInt32 y = zero_extend<UInt32>(gpr[rt(instr)], 32); MulResult<UInt32> r = multiply(x, y); lo = sign_extend<UInt64>(r.lo, 32); hi = sign_extend<UInt64>(r.hi, 32); return nothing_special; } case DIV: { // Divide //////////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tdiv\t%s, %s", pc, regname[rs(instr)], regname[rt(instr)]); Int32 y = sign_extend<Int32>(gpr[rt(instr)], 32); if (y) { Int32 x = sign_extend<Int32>(gpr[rs(instr)], 32); DivResult<Int32> r = divide(x, y); lo = sign_extend<UInt64>(r.quot, 32); hi = sign_extend<UInt64>(r.rem, 32); } return nothing_special; } case DIVU: { // Divide Unsigned /////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tdivu\t%s, %s", pc, regname[rs(instr)], regname[rt(instr)]); UInt32 y = zero_extend<UInt32>(gpr[rt(instr)], 32); if (y) { UInt32 x = zero_extend<UInt32>(gpr[rs(instr)], 32); DivResult<UInt32> r = divide(x, y); lo = sign_extend<UInt64>(r.quot, 32); hi = sign_extend<UInt64>(r.rem, 32); } return nothing_special; } case DMULT: { // Doubleword Multiply /////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tdmult\t%s, %s", pc, regname[rs(instr)], regname[rt(instr)]); if (!allow_xinstr()) process_reserved_instruction(); Int64 x = gpr[rs(instr)]; Int64 y = gpr[rt(instr)]; MulResult<Int64> r = multiply(x, y); lo = sign_extend<UInt64>(r.lo, 64); hi = sign_extend<UInt64>(r.hi, 64); return nothing_special; } case DMULTU: { // Doubleword Multiply Unsigned ////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tdmultu\t%s, %s", pc, regname[rs(instr)], regname[rt(instr)]); if (!allow_xinstr()) process_reserved_instruction(); UInt64 x = zero_extend<UInt64>(gpr[rs(instr)], 64); UInt64 y = zero_extend<UInt64>(gpr[rt(instr)], 64); MulResult<UInt64> r = multiply(x, y); lo = sign_extend<UInt64>(r.lo, 64); hi = sign_extend<UInt64>(r.hi, 64); return nothing_special; } case DDIV: { // Doubleword Divide ///////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tddiv\t%s, %s", pc, regname[rs(instr)], regname[rt(instr)]); if (!allow_xinstr()) process_reserved_instruction(); Int64 y = gpr[rt(instr)]; if (y) { Int64 x = gpr[rs(instr)]; DivResult<Int64> r = divide(x, y); lo = sign_extend<UInt64>(r.quot, 64); hi = sign_extend<UInt64>(r.rem, 64); } return nothing_special; } case DDIVU: { // Doubleword Divide Unsigned //////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tddivu\t%s, %s", pc, regname[rs(instr)], regname[rt(instr)]); if (!allow_xinstr()) process_reserved_instruction(); UInt64 y = zero_extend<UInt64>(gpr[rt(instr)], 64); if (y) { UInt64 x = zero_extend<UInt64>(gpr[rs(instr)], 64); DivResult<UInt64> r = divide(x, y); lo = sign_extend<UInt64>(r.quot, 64); hi = sign_extend<UInt64>(r.rem, 64); } return nothing_special; } case ADD: { // Add /////////////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tadd\t%s, %s, %s", pc, regname[rd(instr)], regname[rs(instr)], regname[rt(instr)]); UInt32 x = gpr[rs(instr)]; UInt32 y = gpr[rt(instr)]; UInt32 z = x + y; // Overflow occurs is sign(x) == sign(y) != sign(z). if (bit(x ^ y, 31) == 0 && bit(x ^ z, 31) != 0) process_integer_overflow(); gpr[rd(instr)] = sign_extend<UInt64>(z, 32); return nothing_special; } case ADDU: { // Add Unsigned ////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\taddu\t%s, %s, %s", pc, regname[rd(instr)], regname[rs(instr)], regname[rt(instr)]); UInt32 x = gpr[rs(instr)]; UInt32 y = gpr[rt(instr)]; gpr[rd(instr)] = sign_extend<UInt64>(x + y, 32); return nothing_special; } case SUB: { // Subtract ////////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsub\t%s, %s, %s", pc, regname[rd(instr)], regname[rs(instr)], regname[rt(instr)]); Int32 x = zero_extend<UInt32>(gpr[rs(instr)], 32); Int32 y = zero_extend<UInt32>(gpr[rt(instr)], 32); Int32 z = UInt32(x) - UInt32(y); if ((y < 0 && z < x) || (y > 0 && z > x)) process_integer_overflow(); gpr[rd(instr)] = sign_extend<UInt64>(z, 32); return nothing_special; } case SUBU: { // Subtract Unsigned ///////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tsubu\t%s, %s, %s", pc, regname[rd(instr)], regname[rs(instr)], regname[rt(instr)]); UInt32 x = zero_extend<UInt32>(gpr[rs(instr)], 32); UInt32 y = zero_extend<UInt32>(gpr[rt(instr)], 32); gpr[rd(instr)] = sign_extend<UInt64>(x - y, 32); return nothing_special; } case AND: { // And /////////////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tand\t%s, %s, %s", pc, regname[rd(instr)], regname[rs(instr)], regname[rt(instr)]); gpr[rd(instr)] = gpr[rs(instr)] & gpr[rt(instr)]; return nothing_special; } case OR: { // Or //////////////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tor\t%s, %s, %s", pc, regname[rd(instr)], regname[rs(instr)], regname[rt(instr)]); gpr[rd(instr)] = gpr[rs(instr)] | gpr[rt(instr)]; return nothing_special; } case XOR: { // Exclusive Or ////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\txor\t%s, %s, %s", pc, regname[rd(instr)], regname[rs(instr)], regname[rt(instr)]); gpr[rd(instr)] = gpr[rs(instr)] ^ gpr[rt(instr)]; return nothing_special; } case NOR: { // Nor /////////////////////////////////////////////////////////// if (trace_level >= print_instructions) log("[%lx]\tnor\t%s, %s, %s", pc, regname[rd(instr)], regname[rs(instr)], regname[rt(instr)]); gpr[rd(instr)] = ~(gpr[rs(instr)] | gpr[rt(instr)]); return nothing_special; } case SLT: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -