//---------------------------------------------------------------------------// // 1100101 |_ mov #0, r4 __ // // 11 |_ <0xb380 %5c4> / _|_ _____ ___ // // 0110 |_ 3.50 -> 3.60 | _\ \ / _ (_-< // // |_ base# + offset |_| /_\_\___/__/ // //---------------------------------------------------------------------------// #include #include #include #include namespace FxOS { //--- // CPU registers //--- char const *regnames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r0_bank", "r1_bank", "r2_bank", "r3_bank", "r4_bank", "r5_bank", "r6_bank", "r7_bank", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "mach", "macl", "pr", "pc", "sr", "ssr", "spc", "gbr", "vbr", "dbr", "sgr" }; /* Construction from string */ CpuRegister::CpuRegister(std::string name) { int regcount = (sizeof regnames / sizeof regnames[0]); char const *name_c = name.c_str(); for(int i = 0; i < regcount; i++) { if(!strcmp(regnames[i], name_c)) { m_name = CpuRegisterName(i+1); return; } } m_name = CpuRegister::UNDEFINED; } /* Conversion to string */ std::string CpuRegister::str() const noexcept { int regcount = (sizeof regnames / sizeof regnames[0]); int i = m_name - 1; if(i < 0 || i >= regcount) return format("", i+1); return regnames[i]; } //--- // Instruction arguments //--- /* External constructors */ Argument Argument_Reg(CpuRegister base) { Argument arg; arg.kind = Argument::Reg; arg.base = base; return arg; } Argument Argument_Deref(CpuRegister base) { Argument arg; arg.kind = Argument::Deref; arg.base = base; return arg; } Argument Argument_PostInc(CpuRegister base) { Argument arg; arg.kind = Argument::PostInc; arg.base = base; return arg; } Argument Argument_PreDec(CpuRegister base) { Argument arg; arg.kind = Argument::PreDec; arg.base = base; return arg; } Argument Argument_StructDeref(int disp, int opsize, CpuRegister base) { Argument arg; arg.kind = Argument::StructDeref; arg.base = base; arg.disp = disp; arg.opsize = opsize; return arg; } Argument Argument_ArrayDeref(CpuRegister index, CpuRegister base) { Argument arg; arg.kind = Argument::ArrayDeref; arg.base = base; arg.index = index; return arg; } Argument Argument_PcRel(int disp, int opsize) { Argument arg; arg.kind = Argument::PcRel; arg.disp = disp; arg.opsize = opsize; return arg; } Argument Argument_PcJump(int disp) { Argument arg; arg.kind = Argument::PcJump; arg.disp = disp; return arg; } Argument Argument_PcAddr(int disp) { Argument arg; arg.kind = Argument::PcAddr; arg.disp = disp; return arg; } Argument Argument_Imm(int imm) { Argument arg; arg.kind = Argument::Imm; arg.imm = imm; return arg; } /* String representation */ std::string Argument::str() const { switch(kind) { case Argument::Reg: return base.str(); case Argument::Deref: return format("@%s", base.str()); case Argument::PostInc: return format("@%s+", base.str()); case Argument::PreDec: return format("@-%s", base.str()); case Argument::StructDeref: return format("@(%d,%s)", disp, base.str().c_str()); case Argument::ArrayDeref: return format("@(%s,%s)", index.str().c_str(), base.str().c_str()); case Argument::PcRel: return format("@(%d,pc)", disp); case Argument::PcJump: return format("pc+%d", disp); case Argument::PcAddr: return format("pc+%u", disp); case Argument::Imm: return format("#%d", imm); default: return "(invalid)"; } } //--- // Instruction management //--- Instruction::Instruction(char const *mn): opcode {0}, opsize {0}, arg_count {0} { int len = strlen(mn); int pos = std::max(0, len - 2); if(!strncmp(mn + pos, ".b", 2)) { opsize = 1; len -= 2; } else if(!strncmp(mn + pos, ".w", 2)) { opsize = 2; len -= 2; } else if(!strncmp(mn + pos, ".l", 2)) { opsize = 4; len -= 2; } len = std::min(len, 11); strncpy(mnemonic, mn, len); mnemonic[len] = 0; } Instruction::Instruction(char const *mn, Argument arg): Instruction(mn) { args[0] = arg; arg_count = 1; } Instruction::Instruction(char const *mn, Argument arg1, Argument arg2): Instruction(mn) { args[0] = arg1; args[1] = arg2; arg_count = 2; } //--- // Instruction classes //--- bool Instruction::isterminal() const noexcept { if(!strcmp(mnemonic, "rte") || !strcmp(mnemonic, "rts")) return true; /* Also jmp @rn which is regarded as a terminal call */ if(!strcmp(mnemonic,"jmp") && args[0].kind == Argument::Deref) return true; /* Same for braf because we can't analyse further */ if(!strcmp(mnemonic, "braf")) return true; return false; } bool Instruction::isjump() const noexcept { return !strcmp(mnemonic, "bra"); } bool Instruction::iscondjump() const noexcept { char const *v[] = { "bf", "bf.s", "bf/s", "bt", "bt.s", "bt/s", NULL, }; for(int i = 0; v[i]; i++) { if(!strcmp(mnemonic, v[i])) return true; } return false; } bool Instruction::isdelayed() const noexcept { char const *v[] = { "rte", "rts", "jmp", "jsr", "bra", "braf", "bsr", "bsrf", "bf.s", "bf/s", "bt.s", "bt/s", NULL, }; for(int i = 0; v[i]; i++) { if(!strcmp(mnemonic, v[i])) return true; } return false; } bool Instruction::isvaliddelayslot() const noexcept { return !isdelayed() && !isterminal() && !isjump() && !iscondjump(); } } /* namespace FxOS */