diff options
author | Oxore <oxore@protonmail.com> | 2024-04-30 00:00:58 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2024-11-21 00:18:24 +0300 |
commit | 85614fc367ba53d0d5ca48873337571fc7f4f5b7 (patch) | |
tree | be53e4f27e915a254f48c0b9f78ecbd91ec6ba76 | |
parent | 2294d3e82e986894c0645840d01ddd6b2cb08523 (diff) |
Some refactoring
-rw-r--r-- | src/common.h | 6 | ||||
-rw-r--r-- | src/m68k.cpp | 126 | ||||
-rw-r--r-- | src/m68k.h | 51 | ||||
-rw-r--r-- | src/main.cpp | 26 |
4 files changed, 115 insertions, 94 deletions
diff --git a/src/common.h b/src/common.h index 94dcca6..e1c57c5 100644 --- a/src/common.h +++ b/src/common.h @@ -74,9 +74,9 @@ constexpr RefKindMask kRef2DataMask = kRef2ReadMask | kRef2WriteMask; // For sec constexpr RefKindMask kRefReadMask = kRef1ReadMask | kRef2ReadMask; // For any argument constexpr RefKindMask kRefWriteMask = kRef1WriteMask | kRef2WriteMask; // For any argument constexpr RefKindMask kRefDataMask = kRefReadMask | kRefWriteMask; -constexpr size_t kInstructionSizeStepBytes = 2; -constexpr size_t kRomSizeBytes = 4 * 1024 * 1024; -constexpr size_t kDisasmMapSizeElements = kRomSizeBytes / kInstructionSizeStepBytes; +constexpr uint32_t kInstructionSizeStepBytes = 2; +constexpr uint32_t kRomSizeBytes = 4 * 1024 * 1024; +constexpr uint32_t kDisasmMapSizeElements = kRomSizeBytes / kInstructionSizeStepBytes; static inline constexpr size_t Min(size_t a, size_t b) { return a < b ? a : b; } diff --git a/src/m68k.cpp b/src/m68k.cpp index 9062fcf..74df143 100644 --- a/src/m68k.cpp +++ b/src/m68k.cpp @@ -1172,10 +1172,7 @@ static size_t disasm_addx_subx_abcd_sbcd( const int xi = (instr >> 9) & 7; const auto src = m ? Arg::AnAddrDecr(xn) : Arg::Dn(xn); const auto dst = m ? Arg::AnAddrDecr(xi) : Arg::Dn(xi); - // XXX GNU AS does not know ABCD.B, it only knows ABCD, but happily consumes - // SBCD.B and others. That's why it is OpSize::kNone specifically for ABCD - // mnemonic. It is probably a bug in GNU AS. - node.op = Op::Typical(opcode, (opcode == OpCode::kABCD) ? OpSize::kNone : opsize, src, dst); + node.op = Op::Typical(opcode, opsize, src, dst); return node.size = kInstructionSizeStepBytes + src.Size(opsize) + dst.Size(opsize); } @@ -1758,16 +1755,6 @@ static const char *ToString(const OpSize s) return ""; } -static int OpcodeSNPrintf( - char *const buf, - const size_t bufsz, - const OpCode opcode, - const Condition condition, - const OpSize size_spec) -{ - return snprintf(buf, bufsz, "%s%s", ToString(opcode, condition), ToString(size_spec)); -} - static char RegChar(const uint8_t xi) { return (xi & 0x08) ? 'a' : 'd'; @@ -1817,55 +1804,56 @@ static size_t snprint_reg_mask( return written; } -int Arg::SNPrint( +int SNPrintArg( char *const buf, const size_t bufsz, + const Arg &arg, const bool imm_as_hex, const RefKindMask ref_kinds, const char *const label, const uint32_t self_addr, - const uint32_t ref_addr) const + const uint32_t ref_addr) { - switch (type) { + switch (arg.type) { case ArgType::kNone: assert(false); break; case ArgType::kRaw: - return snprintf(buf, bufsz, "0x%04x", uword); + return snprintf(buf, bufsz, "0x%04x", arg.uword); case ArgType::kDn: - return snprintf(buf, bufsz, "%%d%d", xn); + return snprintf(buf, bufsz, "%%d%d", arg.xn); case ArgType::kAn: - return snprintf(buf, bufsz, "%%a%u", xn); + return snprintf(buf, bufsz, "%%a%u", arg.xn); case ArgType::kAnAddr: - return snprintf(buf, bufsz, "%%a%u@", xn); + return snprintf(buf, bufsz, "%%a%u@", arg.xn); case ArgType::kAnAddrIncr: - return snprintf(buf, bufsz, "%%a%u@+", xn); + return snprintf(buf, bufsz, "%%a%u@+", arg.xn); case ArgType::kAnAddrDecr: - return snprintf(buf, bufsz, "%%a%u@-", xn); + return snprintf(buf, bufsz, "%%a%u@-", arg.xn); case ArgType::kD16AnAddr: - return snprintf(buf, bufsz, "%%a%u@(%d:w)", d16_an.an, d16_an.d16); + return snprintf(buf, bufsz, "%%a%u@(%d:w)", arg.d16_an.an, arg.d16_an.d16); case ArgType::kD8AnXiAddr: return snprintf( buf, bufsz, "%%a%u@(%d,%%%c%u:%c)", - d8_an_xi.an, - d8_an_xi.d8, - RegChar(d8_an_xi.xi), - RegNum(d8_an_xi.xi), - SizeSpecChar(d8_an_xi.xi)); + arg.d8_an_xi.an, + arg.d8_an_xi.d8, + RegChar(arg.d8_an_xi.xi), + RegNum(arg.d8_an_xi.xi), + SizeSpecChar(arg.d8_an_xi.xi)); case ArgType::kWord: case ArgType::kLong: { - const char c = type == ArgType::kLong ? 'l' : 'w'; + const char c = arg.type == ArgType::kLong ? 'l' : 'w'; if (ref_kinds & kRefAbsMask) { - if (static_cast<uint32_t>(lword) == ref_addr) { + if (static_cast<uint32_t>(arg.lword) == ref_addr) { return snprintf(buf, bufsz, "%s:%c", label, c); } else { // It has to be AFTER the label we are gonna reference here - assert(static_cast<uint32_t>(lword) > ref_addr); - return snprintf(buf, bufsz, "%s+%d:%c", label, lword - ref_addr, c); + assert(static_cast<uint32_t>(arg.lword) > ref_addr); + return snprintf(buf, bufsz, "%s+%d:%c", label, arg.lword - ref_addr, c); } } else { - return snprintf(buf, bufsz, "0x%x:%c", lword, c); + return snprintf(buf, bufsz, "0x%x:%c", arg.lword, c); } } case ArgType::kD16PCAddr: @@ -1873,7 +1861,11 @@ int Arg::SNPrint( // XXX: Most of instructions with PC relative values have 2 bytes // added to the offset, some does not. Still figuring that out. const bool has_fix = ref_kinds & kRefPcRelFix2Bytes; - const uint32_t arg_addr = self_addr + d16_pc.d16 + kInstructionSizeStepBytes + (has_fix ? kInstructionSizeStepBytes : 0); + // XXX: I should try (self_addr + instruction_size - ext_word_size) + // universally instead of hacky fix flag, but it requires some + // overhaul of the instruction printing functions. + const uint32_t arg_addr = self_addr + arg.d16_pc.d16 + kInstructionSizeStepBytes + + (has_fix ? kInstructionSizeStepBytes : 0); if (arg_addr == ref_addr) { return snprintf(buf, bufsz, "%%pc@(%s:w)", label); } else { @@ -1881,42 +1873,42 @@ int Arg::SNPrint( return snprintf(buf, bufsz, "%%pc@(%s+%d:w)", label, arg_addr - ref_addr); } } else { - return snprintf(buf, bufsz, "%%pc@(%d:w)", d16_pc.d16); + return snprintf(buf, bufsz, "%%pc@(%d:w)", arg.d16_pc.d16); } case ArgType::kD8PCXiAddr: return snprintf( buf, bufsz, "%%pc@(%d,%%%c%u:%c)", - d8_pc_xi.d8, - RegChar(d8_pc_xi.xi), - RegNum(d8_pc_xi.xi), - SizeSpecChar(d8_pc_xi.xi)); + arg.d8_pc_xi.d8, + RegChar(arg.d8_pc_xi.xi), + RegNum(arg.d8_pc_xi.xi), + SizeSpecChar(arg.d8_pc_xi.xi)); case ArgType::kImmediate: if (ref_kinds & kRef1ImmMask) { - if (static_cast<uint32_t>(lword) == ref_addr) { + if (static_cast<uint32_t>(arg.lword) == ref_addr) { return snprintf(buf, bufsz, "#%s", label); } else { // It has to be AFTER the label we are gonna reference here - assert(static_cast<uint32_t>(lword) > ref_addr); - return snprintf(buf, bufsz, "#%s+%d", label, lword - ref_addr); + assert(static_cast<uint32_t>(arg.lword) > ref_addr); + return snprintf(buf, bufsz, "#%s+%d", label, arg.lword - ref_addr); } } else if (imm_as_hex) { - return snprintf(buf, bufsz, "#0x%x", lword); + return snprintf(buf, bufsz, "#0x%x", arg.lword); } else { - return snprintf(buf, bufsz, "#%d", lword); + return snprintf(buf, bufsz, "#%d", arg.lword); } case ArgType::kRegMask: case ArgType::kRegMaskPredecrement: - return snprint_reg_mask(buf, bufsz, uword, type); + return snprint_reg_mask(buf, bufsz, arg.uword, arg.type); case ArgType::kDisplacement: if (ref_kinds & kRefRelMask) { - if (static_cast<uint32_t>(self_addr + lword) == ref_addr) { + if (static_cast<uint32_t>(self_addr + arg.lword) == ref_addr) { return snprintf(buf, bufsz, "%s", label); } else { - assert(static_cast<uint32_t>(self_addr + lword) > ref_addr); - return snprintf(buf, bufsz, "%s+%d", label, (self_addr + lword) - ref_addr); + assert(static_cast<uint32_t>(self_addr + arg.lword) > ref_addr); + return snprintf(buf, bufsz, "%s+%d", label, (self_addr + arg.lword) - ref_addr); } } else { - return snprintf(buf, bufsz, ".%s%d", lword >= 0 ? "+" : "", lword); + return snprintf(buf, bufsz, ".%s%d", arg.lword >= 0 ? "+" : "", arg.lword); } case ArgType::kCCR: return snprintf(buf, bufsz, "%%ccr"); @@ -1929,8 +1921,9 @@ int Arg::SNPrint( return -1; } -int Op::FPrint( +int FPrintOp( FILE *const stream, + const Op &op, const char *const indent, const bool imm_as_hex, const RefKindMask ref_kinds, @@ -1938,12 +1931,21 @@ int Op::FPrint( const char *const ref2_label, const uint32_t self_addr, const uint32_t ref1_addr, - const uint32_t ref2_addr) const + const uint32_t ref2_addr) { - assert(opcode != OpCode::kNone); + assert(op.opcode != OpCode::kNone); char mnemonic_str[kMnemonicBufferSize]{}; - OpcodeSNPrintf(mnemonic_str, kMnemonicBufferSize, opcode, condition, size_spec); - if (arg1.type != ArgType::kNone) { + // XXX GNU AS does not know ABCD.B, it only knows ABCD, but happily consumes + // SBCD.B and others. That's why it is OpSize::kNone specifically for ABCD + // mnemonic. It is probably a bug in GNU AS. + const OpSize size_spec{(op.opcode == OpCode::kABCD) ? OpSize::kNone : op.size_spec}; + snprintf( + mnemonic_str, + kMnemonicBufferSize, + "%s%s", + ToString(op.opcode, op.condition), + ToString(size_spec)); + if (op.arg1.type != ArgType::kNone) { char arg1_str[kArgsBufferSize]{}; const RefKindMask ref1_kinds = ref_kinds & (kRef1Mask | kRefPcRelFix2Bytes); // It is useful to have immediate value printed as hex if destination @@ -1951,23 +1953,25 @@ int Op::FPrint( // register. USP is not the case because it's value may be moved only to // or from An register. const bool imm_as_hex_2 = imm_as_hex || - arg2.type == ArgType::kAn || - arg2.type == ArgType::kCCR || - arg2.type == ArgType::kSR; - arg1.SNPrint( + op.arg2.type == ArgType::kAn || + op.arg2.type == ArgType::kCCR || + op.arg2.type == ArgType::kSR; + SNPrintArg( arg1_str, kArgsBufferSize, + op.arg1, imm_as_hex_2, ref1_kinds, ref1_label, self_addr, ref1_addr); - if (arg2.type != ArgType::kNone) { + if (op.arg2.type != ArgType::kNone) { char arg2_str[kArgsBufferSize]{}; const RefKindMask ref2_kinds = ref_kinds & (kRef2Mask | kRefPcRelFix2Bytes); - arg2.SNPrint( + SNPrintArg( arg2_str, kArgsBufferSize, + op.arg2, false, ref2_kinds, ref2_label, @@ -294,14 +294,6 @@ struct Arg { a.uword = instr; return a; } - int SNPrint( - char *buf, - size_t bufsz, - bool imm_as_hex = false, - RefKindMask ref_kinds = 0, - const char *label = nullptr, - uint32_t self_addr = 0, - uint32_t ref_addr = 0) const; }; struct Op { @@ -323,16 +315,6 @@ struct Op { { return Op::Typical(OpCode::kRaw, OpSize::kNone, Arg::Raw(instr)); } - int FPrint( - FILE *, - const char *indent, - bool imm_as_hex, - RefKindMask ref_kinds = 0, - const char *ref1_label = nullptr, - const char *ref2_label = nullptr, - uint32_t self_addr = 0, - uint32_t ref1_addr = 0, - uint32_t ref2_addr = 0) const; }; constexpr size_t kMnemonicBufferSize = 10; @@ -342,3 +324,36 @@ static constexpr inline bool IsBRA(Op op) { return op.opcode == OpCode::kBcc && op.condition == Condition::kT; } + +int SNPrintArg( + char *buf, + size_t bufsz, + const Arg &, + bool imm_as_hex = false, + RefKindMask ref_kinds = 0, + const char *label = nullptr, + uint32_t self_addr = 0, + uint32_t ref_addr = 0); + +/// Return value means nothing and should be ignored +int FPrintOp( + FILE *, + const Op &op, + const char *const indent, + const bool imm_as_hex, + RefKindMask ref_kinds = 0, + const char *ref1_label = nullptr, + const char *ref2_label = nullptr, + uint32_t self_addr = 0, + uint32_t ref1_addr = 0, + uint32_t ref2_addr = 0); + +constexpr size_t BaseInstructionSize(OpCode opcode) +{ + switch (opcode) { + case OpCode::kMOVEM: + return 2 * kInstructionSizeStepBytes; + default: break; + } + return kInstructionSizeStepBytes; +} diff --git a/src/main.cpp b/src/main.cpp index 802e87b..4e49fde 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -336,13 +336,16 @@ static bool EmitNodeDisassembly( } assert(node.op.opcode != OpCode::kNone); if (ShouldPrintAsRaw(node.op)) { - Op::Raw(GetU16BE(code.buffer + node.address)) - .FPrint(output, s.indent, s.imm_hex); + FPrintOp( + output, + Op::Raw(GetU16BE(code.buffer + node.address)), + s.indent, + s.imm_hex); uint32_t i = kInstructionSizeStepBytes; for (; i < node.size; i += kInstructionSizeStepBytes) { char arg_str[kArgsBufferSize]{}; const auto arg = Arg::Raw(GetU16BE(code.buffer + node.address + i)); - arg.SNPrint(arg_str, kArgsBufferSize); + SNPrintArg(arg_str, kArgsBufferSize, arg); fprintf(output, ", %s", arg_str); } } else { @@ -397,8 +400,9 @@ static bool EmitNodeDisassembly( snprintf(ref2_label, (sizeof ref2_label), "L%08x", ref2_addr); } } - node.op.FPrint( + FPrintOp( output, + node.op, s.indent, s.imm_hex, ref_kinds, @@ -415,7 +419,7 @@ static bool EmitNodeDisassembly( fprintf(output, " | XREF2 @%08x", ref2_addr); } } else { - node.op.FPrint(output, s.indent, s.imm_hex); + FPrintOp(output, node.op, s.indent, s.imm_hex); } } if (s.raw_data_comment && (traced || s.raw_data_comment_all)) { @@ -447,10 +451,8 @@ static void EmitNonCodeSymbols( } } -constexpr const char *kSplitMarkerx32 = +constexpr const char *kSplitMarker = "\n| ---------------- >8 split_marker %08" PRIx32 " 8< ----------------\n"; -constexpr const char *kSplitMarkerzx = - "\n| ---------------- >8 split_marker %08zx 8< ----------------\n"; static FILE *SplitIfRequired( const EmitContext &ctx, @@ -479,7 +481,7 @@ static FILE *SplitIfRequired( if (s.output_dir_path) { return OpenNewPartFile(s.output_dir_path, node.address); } else { - fprintf(ctx.output, kSplitMarkerx32, node.address); + fprintf(ctx.output, kSplitMarker, node.address); return ctx.output; } } @@ -493,7 +495,7 @@ static FILE *SplitIfRequired( if (s.output_dir_path) { return OpenNewPartFile(s.output_dir_path, node.address); } else { - fprintf(ctx.output, kSplitMarkerx32, node.address); + fprintf(ctx.output, kSplitMarker, node.address); return ctx.output; } } @@ -502,7 +504,7 @@ static FILE *SplitIfRequired( if (s.output_dir_path) { return OpenNewPartFile(s.output_dir_path, node.address); } else { - fprintf(ctx.output, kSplitMarkerx32, node.address); + fprintf(ctx.output, kSplitMarker, node.address); return ctx.output; } } @@ -591,7 +593,7 @@ static bool EmitDisassembly( fclose(ctx.output); ctx.output = output; } else { - fprintf(ctx.output, kSplitMarkerzx, kRomSizeBytes); + fprintf(ctx.output, kSplitMarker, kRomSizeBytes); } } EmitNonCodeSymbols(ctx.output, disasm_map, code, s); |