From 672ec345c6eb5a06500cba10e3f329b8a65ee047 Mon Sep 17 00:00:00 2001 From: Amlal El Mahrouss <113760121+Amlal-ElMahrouss@users.noreply.github.com> Date: Fri, 5 Apr 2024 04:43:27 +0200 Subject: ppcasm: WiP: Add opcode table for PowerPC. What is needed to be done: - Support registers and jump addresses inside a PowerPC assembly file. - Thoroughly test the output on a PowerPC emulator. Signed-off-by: Amlal El Mahrouss <113760121+Amlal-ElMahrouss@users.noreply.github.com> --- Sources/64asm.cc | 2 +- Sources/i64asm.cc | 14 +++++------ Sources/ppc-cc.cc | 4 ++-- Sources/ppcasm.cc | 70 ++++++++++++++++++++++++++++++------------------------- 4 files changed, 48 insertions(+), 42 deletions(-) (limited to 'Sources') diff --git a/Sources/64asm.cc b/Sources/64asm.cc index 78fa590..50b2d0b 100644 --- a/Sources/64asm.cc +++ b/Sources/64asm.cc @@ -560,7 +560,7 @@ bool CompilerKit::Encoder64x0::WriteNumber(const std::size_t &pos, !res) { if (errno != 0) { detail::print_error("invalid hex number: " + jump_label, "64asm"); - throw std::runtime_error("invalid_hex"); + throw std::runtime_error("invalid_hex_number"); } } diff --git a/Sources/i64asm.cc b/Sources/i64asm.cc index 0eae5fc..e578587 100644 --- a/Sources/i64asm.cc +++ b/Sources/i64asm.cc @@ -124,29 +124,29 @@ MPCC_MODULE(NewOSAssemblerAMD64) { "jno", "jnp", "jns", "jnz", "jo", "jp", "jpe", "jpo", "js", "jz"}; for (i64_hword_t i = 0; i < kJumpLimit; i++) { - CpuCodeAMD64 code{.fName = opcodes_jump[i], + CpuOpcodeAMD64 code{.fName = opcodes_jump[i], .fOpcode = static_cast(kAsmJumpOpcode + i)}; kOpcodesAMD64.push_back(code); } - CpuCodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; + CpuOpcodeAMD64 code{.fName = "jcxz", .fOpcode = 0xE3}; kOpcodesAMD64.push_back(code); for (i64_hword_t i = kJumpLimitStandard; i < kJumpLimitStandardLimit; i++) { - CpuCodeAMD64 code{.fName = "jmp", .fOpcode = i}; + CpuOpcodeAMD64 code{.fName = "jmp", .fOpcode = i}; kOpcodesAMD64.push_back(code); } - CpuCodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; + CpuOpcodeAMD64 lahf{.fName = "lahf", .fOpcode = 0x9F}; kOpcodesAMD64.push_back(lahf); - CpuCodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; + CpuOpcodeAMD64 lds{.fName = "lds", .fOpcode = 0xC5}; kOpcodesAMD64.push_back(lds); - CpuCodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; + CpuOpcodeAMD64 lea{.fName = "lea", .fOpcode = 0x8D}; kOpcodesAMD64.push_back(lea); - CpuCodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; + CpuOpcodeAMD64 nop{.fName = "nop", .fOpcode = 0x90}; kOpcodesAMD64.push_back(nop); //////////////// CPU OPCODES END //////////////// diff --git a/Sources/ppc-cc.cc b/Sources/ppc-cc.cc index 78f9bc1..25dd74e 100644 --- a/Sources/ppc-cc.cc +++ b/Sources/ppc-cc.cc @@ -1155,8 +1155,8 @@ class AssemblyMountpointCLang final : public CompilerKit::AssemblyInterface { if (kAcceptableErrors > 0) return -1; - std::vector keywords = {"ldw", "stw", "lda", "sta", - "add", "dec", "mv"}; + std::vector keywords = {"ld", "stw", + "add", "sub", "or"}; /// /// Replace, optimize, fix assembly output. diff --git a/Sources/ppcasm.cc b/Sources/ppcasm.cc index f37a650..0214053 100644 --- a/Sources/ppcasm.cc +++ b/Sources/ppcasm.cc @@ -43,7 +43,7 @@ #define kStdOut (std::cout << kWhite) #define kStdErr (std::cout << kRed) -static char kOutputArch = CompilerKit::kPefArchPowerPC; +static CharType kOutputArch = CompilerKit::kPefArchPowerPC; static Boolean kOutputAsBinary = false; static UInt32 kErrorLimit = 10; @@ -56,7 +56,7 @@ static std::vector> kOriginLabel; static bool kVerbose = false; -static std::vector kBytes; +static std::vector kBytes; static CompilerKit::AERecordHeader kCurrentRecord{ .fName = "", .fKind = CompilerKit::kPefCode, .fSize = 0, .fOffset = 0}; @@ -506,15 +506,13 @@ std::string CompilerKit::EncoderPowerPC::CheckLine( } // these do take an argument. - std::vector operands_inst = {"stw", "ldw", "lda", "sta"}; + std::vector operands_inst = {"stw", "ld", "lda", "sta"}; // these don't. - std::vector filter_inst = {"jlr", "jrl", "int"}; - - for (auto &opcode64x0 : kOpcodes64x0) { - if (line.find(opcode64x0.fName) != std::string::npos) { - if (opcode64x0.fFunct7 == kAsmNoArgs) return err_str; + std::vector filter_inst = {"blr", "bl", "sc"}; + for (auto &opcodePPC : kOpcodesPowerPC) { + if (line.find(opcodePPC.name) != std::string::npos) { for (auto &op : operands_inst) { // if only the instruction was found. if (line == op) { @@ -527,13 +525,13 @@ std::string CompilerKit::EncoderPowerPC::CheckLine( // if it is like that -> addr1, 0x0 if (auto it = std::find(filter_inst.begin(), filter_inst.end(), - opcode64x0.fName); + opcodePPC.name); it == filter_inst.cend()) { - if (ParserKit::find_word(line, opcode64x0.fName)) { - if (!isspace(line[line.find(opcode64x0.fName) + - strlen(opcode64x0.fName)])) { + if (ParserKit::find_word(line, opcodePPC.name)) { + if (!isspace(line[line.find(opcodePPC.name) + + strlen(opcodePPC.name)])) { err_str += "\nMissing space between "; - err_str += opcode64x0.fName; + err_str += opcodePPC.name; err_str += " and operands.\nhere -> "; err_str += line; } @@ -660,22 +658,20 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, const std::string &file) { if (ParserKit::find_word(line, "export ")) return true; - for (auto &opcode64x0 : kOpcodes64x0) { + for (auto &opcodePPC : kOpcodesPowerPC) { // strict check here - if (ParserKit::find_word(line, opcode64x0.fName) && + if (ParserKit::find_word(line, opcodePPC.name) && detail::algorithm::is_valid(line)) { - std::string name(opcode64x0.fName); + std::string name(opcodePPC.name); std::string jump_label, cpy_jump_label; - kBytes.emplace_back(opcode64x0.fOpcode); - kBytes.emplace_back(opcode64x0.fFunct3); - kBytes.emplace_back(opcode64x0.fFunct7); + kBytes.emplace_back(opcodePPC.opcode); // check funct7 type. - switch (opcode64x0.fFunct7) { + switch (opcodePPC.ops->type) { // reg to reg means register to register transfer operation. - case kAsmRegToReg: - case kAsmImmediate: { + case GREG: + case G0REG: { // \brief how many registers we found. std::size_t found_some = 0UL; @@ -703,7 +699,7 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, reg_str += line[line_index + 3]; detail::print_error( "invalid register index, r" + reg_str + - "\nnote: The PowerPC accepts registers from r0 to r20.", + "\nnote: The PowerPC accepts registers from r0 to r30.", file); throw std::runtime_error("invalid_register_index"); } @@ -712,6 +708,15 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, // finally cast to a size_t std::size_t reg_index = strtol(reg_str.c_str(), nullptr, 10); + uint8_t base = 0x08; + + for (size_t i = 0; i != reg_index; i++) + { + base += 2; + } + + kBytes.emplace_back(base); + if (reg_index > kAsmRegisterLimit) { detail::print_error("invalid register index, r" + reg_str, file); @@ -730,7 +735,7 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, } // we're not in immediate addressing, reg to reg. - if (opcode64x0.fFunct7 != kAsmImmediate) { + if (opcodePPC.ops->type != GREG) { // remember! register to register! if (found_some == 1) { detail::print_error( @@ -738,11 +743,12 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, "starts with 'r'.\nline: " + line, file); + throw std::runtime_error("not_a_register"); } } - if (found_some < 1 && name != "ldw" && name != "lda" && + if (found_some < 1 && name != "ld" && name != "stw") { detail::print_error( "invalid combination of opcode and registers.\nline: " + line, @@ -774,12 +780,12 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, } // try to fetch a number from the name - if (name == "stw" || name == "ldw" || name == "lda" || name == "sta") { + if (name.find("stw") != std::string::npos || name.find("ld") != std::string::npos) { auto where_string = name; // if we load something, we'd need it's symbol/literal - if (name == "stw" || name == "sta" || name == "ldw" || name == "lda" || - name == "sta") + // @note: Something may jump on it, dont remove that if. + if (name.find("stw") != std::string::npos || name.find("ld") != std::string::npos) where_string = ","; jump_label = line; @@ -841,7 +847,7 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, } // This is the case where we jump to a label, it is also used as a goto. - if (name == "lda" || name == "sta") { + if (name == "ld" || name == "stw") { asm_write_label: if (cpy_jump_label.find('\n') != std::string::npos) cpy_jump_label.erase(cpy_jump_label.find('\n'), 1); @@ -903,10 +909,10 @@ bool CompilerKit::EncoderPowerPC::WriteLine(std::string &line, } /// don't go any further if: - /// load word (ldw) or store word. (stw) + /// load word (ld) or store word. (stw) - if (name == "ldw" || - name == "stw") + if (name.find("ld") != std::string::npos || + name.find("st") != std::string::npos) break; auto mld_reloc_str = std::to_string(cpy_jump_label.size()); -- cgit v1.2.3