#include #include #include #include #include #include namespace FxOS { //--- // CPU registers //--- using Reg = CpuRegister::CpuRegisterName; static std::map regnames = { { Reg::R0, "r0" }, { Reg::R1, "r1" }, { Reg::R2, "r2" }, { Reg::R3, "r3" }, { Reg::R4, "r4" }, { Reg::R5, "r5" }, { Reg::R6, "r6" }, { Reg::R7, "r7" }, { Reg::R0B, "r0_bank" }, { Reg::R1B, "r1_bank" }, { Reg::R2B, "r2_bank" }, { Reg::R3B, "r3_bank" }, { Reg::R4B, "r4_bank" }, { Reg::R5B, "r5_bank" }, { Reg::R6B, "r6_bank" }, { Reg::R7B, "r7_bank" }, { Reg::R8, "r8" }, { Reg::R9, "r9" }, { Reg::R10, "r10" }, { Reg::R11, "r11" }, { Reg::R12, "r12" }, { Reg::R13, "r13" }, { Reg::R14, "r14" }, { Reg::R15, "r15" }, { Reg::MACH, "mach" }, { Reg::MACL, "macl" }, { Reg::PR, "pr" }, { Reg::PC, "pc" }, { Reg::SR, "sr" }, { Reg::SSR, "ssr" }, { Reg::SPC, "spc" }, { Reg::GBR, "gbr" }, { Reg::VBR, "vbr" }, { Reg::DBR, "dbr" }, { Reg::SGR, "sgr" }, }; /* Construction from string - pretty slow */ CpuRegister::CpuRegister(std::string name) { for(auto &it: regnames) if(it.second == name) { m_name = it.first; return; } throw std::invalid_argument("invalid CpuRegister name"); } /* Conversion to string */ std::string CpuRegister::str() const noexcept { return regnames.at(m_name); } //--- // 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 */