diff options
author | Oxore <oxore@protonmail.com> | 2023-04-21 18:42:46 +0300 |
---|---|---|
committer | Oxore <oxore@protonmail.com> | 2023-04-21 18:42:46 +0300 |
commit | 8856f2ee0e19f50c4c4fb3dc7fccc8150a00da81 (patch) | |
tree | 575d6b65bf425a27d487f6987c6331763e388ec8 | |
parent | 25762ee11dadb333f5b63c359abb615dc5f16b09 (diff) |
Refactor asm rendering
-rw-r--r-- | CMakeLists.txt | 2 | ||||
-rw-r--r-- | common.h | 24 | ||||
-rw-r--r-- | data_buffer.cpp | 25 | ||||
-rw-r--r-- | data_buffer.h | 14 | ||||
-rw-r--r-- | disasm.cpp | 157 | ||||
-rw-r--r-- | disasm.h | 21 | ||||
-rw-r--r-- | main.cpp | 199 | ||||
-rw-r--r-- | test.bash | 3 |
8 files changed, 255 insertions, 190 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 29bcba0..198fa27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address -fn set(m68kdisasm_sources main.cpp + data_buffer.cpp + disasm.cpp ) add_executable(m68k-disasm ${m68kdisasm_sources}) diff --git a/common.h b/common.h new file mode 100644 index 0000000..ab7a359 --- /dev/null +++ b/common.h @@ -0,0 +1,24 @@ +#pragma once + +constexpr size_t kInstructionSizeStepBytes = 2; + +static inline size_t Min(size_t a, size_t b) { return a < b ? a : b; } + +static inline uint16_t GetU16BE(uint8_t *buffer) +{ + return (static_cast<uint16_t>(buffer[0]) << 8) | static_cast<uint16_t>(buffer[1]); +} + +static inline int16_t GetI16BE(uint8_t *buffer) +{ + return (static_cast<uint16_t>(buffer[0]) << 8) | static_cast<uint16_t>(buffer[1]); +} + +static inline int32_t GetI32BE(uint8_t *buffer) +{ + return (static_cast<uint32_t>(buffer[0]) << 24) | + (static_cast<uint32_t>(buffer[1]) << 16) | + (static_cast<uint32_t>(buffer[2]) << 8) | + static_cast<uint32_t>(buffer[3]); +} + diff --git a/data_buffer.cpp b/data_buffer.cpp new file mode 100644 index 0000000..e691b97 --- /dev/null +++ b/data_buffer.cpp @@ -0,0 +1,25 @@ +#include "data_buffer.h" + +#include <cassert> +#include <cstring> + +void DataBuffer::Expand(size_t new_size) +{ + if (new_size <= buffer_size) { + return; + } + uint8_t *new_buffer{new uint8_t[new_size]}; + assert(new_buffer); + memcpy(new_buffer, buffer, occupied_size); + delete [] buffer; + buffer = new_buffer; + buffer_size = new_size; +} + +DataBuffer::~DataBuffer() +{ + delete [] buffer; + buffer = nullptr; + buffer_size = 0; + occupied_size = 0; +} diff --git a/data_buffer.h b/data_buffer.h new file mode 100644 index 0000000..c3d86e8 --- /dev/null +++ b/data_buffer.h @@ -0,0 +1,14 @@ +#pragma once + +#include <cstddef> +#include <cstdint> + +struct DataBuffer { + static constexpr size_t kInitialSize = 4 * 1024; + uint8_t *buffer{new uint8_t[kInitialSize]}; + size_t buffer_size{kInitialSize}; + size_t occupied_size{}; + void Expand(size_t new_size); + ~DataBuffer(); +}; + diff --git a/disasm.cpp b/disasm.cpp new file mode 100644 index 0000000..033349b --- /dev/null +++ b/disasm.cpp @@ -0,0 +1,157 @@ +#include "disasm.h" +#include "data_buffer.h" +#include "common.h" + +#include <cstdio> + +static size_t disasm_verbatim( + char *out, size_t out_sz, size_t *instr_sz, uint16_t instr, uint32_t, const DataBuffer &) +{ + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes; + } + return Min(out_sz, snprintf(out, out_sz, " .short 0x%04x", instr)); +} + +static size_t disasm_mfff0_v4e70( + char *out, size_t out_sz, size_t *instr_sz, uint16_t instr, uint32_t offset, const DataBuffer &code) +{ + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes; + } + if (instr == 0x4e70) { + return Min(out_sz, snprintf(out, out_sz, " reset")); + } else if (instr == 0x4e71) { + return Min(out_sz, snprintf(out, out_sz, " nop")); + } else if (instr == 0x4e73) { + return Min(out_sz, snprintf(out, out_sz, " rte")); + } else if (instr == 0x4e75) { + return Min(out_sz, snprintf(out, out_sz, " rts")); + } else if (instr == 0x4e76) { + return Min(out_sz, snprintf(out, out_sz, " trapv")); + } else if (instr == 0x4e77) { + return Min(out_sz, snprintf(out, out_sz, " rtr")); + } + return disasm_verbatim(out, out_sz, instr_sz, instr, offset, code); +} + +static size_t disasm_jsr( + char *out, size_t out_sz, size_t *instr_sz, uint16_t instr, uint32_t offset, const DataBuffer & code) +{ + const int addrmode = instr & 0x3f; + const int m = (addrmode >> 3) & 0x7; + const int xn = addrmode & 0x7; + switch (m) { + case 0: // 4e80 .. 4e87 + case 1: // 4e88 .. 4e8f + break; + case 2: // 4e90 .. 4e97 + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes; + } + return Min(out_sz, snprintf(out, out_sz, " jsr %%a%d@", xn)); + case 3: // 4e98 .. 4e9f + case 4: // 4ea0 .. 4ea7 + break; + case 5: // 4ea8 .. 4eaf, Displacement + { + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes * 2; + } + const int16_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); + return Min(out_sz, snprintf(out, out_sz, " jsr %%a%d@(%d:w)", xn, dispmt)); + } + case 6: // 4eb0 .. 4eb7, Brief Extension Word + { + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes * 2; + } + const uint16_t briefext = GetU16BE(code.buffer + offset + kInstructionSizeStepBytes); + const char reg = ((briefext >> 15) & 1) ? 'a' : 'd'; + const int xn2 = (briefext >> 12) & 7; + const char size_spec = ((briefext >> 11) & 1) ? 'l' : 'w'; + const int8_t dispmt = briefext & 0xff; + return Min(out_sz, snprintf( + out, out_sz, " jsr %%a%d@(%d,%%%c%d:%c)", + xn, dispmt, reg, xn2, size_spec)); + } + case 7: // 4eb8 .. 4ebf, some are with Brief Extension Word + switch (xn) { + case 0: // 4eb8 (xxx).W + { + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes * 2; + } + const int32_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); + return Min(out_sz, snprintf(out, out_sz, " jsr 0x%x:w", dispmt)); + } + case 1: // 4eb9 (xxx).L + { + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes * 3; + } + const int32_t dispmt = GetI32BE(code.buffer + offset + kInstructionSizeStepBytes); + return Min(out_sz, snprintf(out, out_sz, " jsr 0x%x:l", dispmt)); + } + case 2: // 4eba, Displacement + { + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes * 2; + } + const int16_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); + return Min(out_sz, snprintf(out, out_sz, " jsr %%pc@(%d:w)", dispmt)); + } + case 3: // 4ebb + { + if (instr_sz) { + *instr_sz = kInstructionSizeStepBytes * 2; + } + const uint16_t briefext = GetU16BE( + code.buffer + offset + kInstructionSizeStepBytes); + const char reg = ((briefext >> 15) & 1) ? 'a' : 'd'; + const int xn2 = (briefext >> 12) & 7; + const char size_spec = ((briefext >> 11) & 1) ? 'l' : 'w'; + const int8_t dispmt = briefext & 0xff; + return Min(out_sz, snprintf( + out, out_sz, " jsr %%pc@(%d,%%%c%d:%c)", dispmt, reg, xn2, size_spec)); + } + case 4: // 4ebc + case 5: // 4ebd + case 6: // 4ebe + break; + } + break; + } + return disasm_verbatim(out, out_sz, instr_sz, instr, offset, code); +} + +size_t m68k_disasm( + char *out, size_t out_sz, size_t *instr_sz, uint16_t instr, uint32_t offset, const DataBuffer &code) +{ + if ((instr & 0xfff0) == 0x4e70) { + return disasm_mfff0_v4e70(out, out_sz, instr_sz, instr, offset, code); + } else if ((instr & 0xffc0) == 0x4e80) { + return disasm_jsr(out, out_sz, instr_sz, instr, offset, code); + } + return disasm_verbatim(out, out_sz, instr_sz, instr, offset, code); +} + +size_t m68k_render_raw_data_comment( + char *out, size_t out_sz, uint32_t offset, size_t instr_sz, const DataBuffer &code) +{ + size_t overall_sz = Min(out_sz, snprintf(out, out_sz, " |")); + for (size_t i = 0; i < instr_sz; i += kInstructionSizeStepBytes) + { + overall_sz += Min( + out_sz - overall_sz, + snprintf( + out + overall_sz, + out_sz - overall_sz, + " %04x", + GetU16BE(code.buffer + offset + i))); + } + overall_sz += Min( + out_sz - overall_sz, + snprintf(out + overall_sz, out_sz - overall_sz, " @%08x", offset)); + return overall_sz; +} diff --git a/disasm.h b/disasm.h new file mode 100644 index 0000000..c166099 --- /dev/null +++ b/disasm.h @@ -0,0 +1,21 @@ +#pragma once + +#include "data_buffer.h" + +#include <cstddef> +#include <cstdint> + +size_t m68k_disasm( + char *out, + size_t out_sz, + size_t *instr_sz, + uint16_t instr, + uint32_t offset, + const DataBuffer &code); + +size_t m68k_render_raw_data_comment( + char *out, + size_t out_sz, + uint32_t offset, + size_t instr_sz, + const DataBuffer &code); @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: Unlicense */ +#include "disasm.h" +#include "data_buffer.h" +#include "common.h" + #define OPTPARSE_IMPLEMENTATION #define OPTPARSE_API static #include "optparse/optparse.h" @@ -8,9 +12,9 @@ #include <cassert> #include <cinttypes> #include <cstdio> +#include <cstdint> #include <cstdlib> #include <cstring> -#include <cstdint> #include <cerrno> #include <climits> @@ -27,32 +31,6 @@ * Trace data parser is needed. Maybe just using atol(3) will be ok. */ -constexpr size_t kInstructionSizeStepBytes = 2; - -struct DataBuffer { - static constexpr size_t kInitialSize = 4 * 1024; - uint8_t *buffer{new uint8_t[kInitialSize]}; - size_t buffer_size{kInitialSize}; - size_t occupied_size{}; - void Expand(size_t new_size) { - if (new_size <= buffer_size) { - return; - } - uint8_t *new_buffer{new uint8_t[new_size]}; - assert(new_buffer); - memcpy(new_buffer, buffer, occupied_size); - delete [] buffer; - buffer = new_buffer; - buffer_size = new_size; - } - ~DataBuffer() { - delete [] buffer; - buffer = nullptr; - buffer_size = 0; - occupied_size = 0; - } -}; - enum class TracedNodeType { kInstruction, kData, @@ -68,166 +46,6 @@ struct DisasmNode { ~DisasmNode(); }; -static size_t disasm_verbatim( - char *out, size_t out_sz, uint16_t instr, uint32_t offset, const DataBuffer &) -{ - snprintf(out, out_sz, " .short 0x%04x | traced @%08x\n", instr, offset); - return kInstructionSizeStepBytes; -} - -static size_t disasm_mfff0_v4e70( - char *out, size_t out_sz, uint16_t instr, uint32_t offset, const DataBuffer &code) -{ - if (instr == 0x4e70) { - snprintf(out, out_sz, " reset | %04x @%08x\n", instr, offset); - } else if (instr == 0x4e71) { - snprintf(out, out_sz, " nop | %04x @%08x\n", instr, offset); - } else if (instr == 0x4e72) { - snprintf(out, out_sz, " .short 0x%04x | stop (not implemented) @%08x\n", instr, offset); - } else if (instr == 0x4e73) { - snprintf(out, out_sz, " rte | %04x @%08x\n", instr, offset); - } else if (instr == 0x4e75) { - snprintf(out, out_sz, " rts | %04x @%08x\n", instr, offset); - } else if (instr == 0x4e76) { - snprintf(out, out_sz, " trapv | %04x @%08x\n", instr, offset); - } else if (instr == 0x4e77) { - snprintf(out, out_sz, " rtr | %04x @%08x\n", instr, offset); - } else { - return disasm_verbatim(out, out_sz, instr, offset, code); - } - return kInstructionSizeStepBytes; -} - -static inline uint16_t GetU16BE(uint8_t *buffer) -{ - return (static_cast<uint16_t>(buffer[0]) << 8) | static_cast<uint16_t>(buffer[1]); -} - -static inline int16_t GetI16BE(uint8_t *buffer) -{ - return (static_cast<uint16_t>(buffer[0]) << 8) | static_cast<uint16_t>(buffer[1]); -} - -static inline int32_t GetI32BE(uint8_t *buffer) -{ - return (static_cast<uint32_t>(buffer[0]) << 24) | - (static_cast<uint32_t>(buffer[1]) << 16) | - (static_cast<uint32_t>(buffer[2]) << 8) | - static_cast<uint32_t>(buffer[3]); -} - -static size_t disasm_jsr( - char *out, size_t out_sz, uint16_t instr, uint32_t offset, const DataBuffer & code) -{ - const int addrmode = instr & 0x3f; - const int m = (addrmode >> 3) & 0x7; - const int xn = addrmode & 0x7; - switch (m) { - case 0: // 4e80 .. 4e87 - case 1: // 4e88 .. 4e8f - return disasm_verbatim(out, out_sz, instr, offset, code); - case 2: // 4e90 .. 4e97 - snprintf(out, out_sz, " jsr %%a%d@ | %04x @%08x\n", xn, instr, offset); - return kInstructionSizeStepBytes; - case 3: // 4e98 .. 4e9f - case 4: // 4ea0 .. 4ea7 - return disasm_verbatim(out, out_sz, instr, offset, code); - case 5: // 4ea8 .. 4eaf, Displacement - { - const int16_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); - const uint16_t dispmt_u = static_cast<uint16_t>(dispmt); - snprintf( - out, out_sz, - " jsr %%a%d@(%d:w) | %04x %04x @%08x\n", - xn, dispmt, instr, dispmt_u, offset); - return 4; - } - break; - case 6: // 4eb0 .. 4eb7, Brief Extension Word - { - const uint16_t briefext = GetU16BE(code.buffer + offset + kInstructionSizeStepBytes); - const int m_0d_1a = (briefext >> 15) & 1; - const int xn2 = (briefext >> 12) & 7; - const int s_0w_1l = (briefext >> 11) & 1; - const int8_t dispmt = briefext & 0xff; - snprintf( - out, out_sz, - " jsr %%a%d@(%d,%%%c%d:%c) | %04x %04x @%08x\n", - xn, dispmt, m_0d_1a ? 'a' : 'd', xn2, s_0w_1l ? 'l' : 'w', instr, briefext, offset); - return 4; - } - break; - case 7: // 4eb8 .. 4ebf, some are with Brief Extension Word - switch (xn) { - case 0: // 4eb8 (xxx).W - { - const int32_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); - const uint16_t dispmt_u = static_cast<uint16_t>(dispmt); - snprintf( - out, out_sz, - " jsr 0x%x:w | %04x %04x @%08x\n", - dispmt, instr, dispmt_u, offset); - return 4; - } - return disasm_verbatim(out, out_sz, instr, offset, code); - case 1: // 4eb9 (xxx).L - { - const int32_t dispmt = GetI32BE(code.buffer + offset + kInstructionSizeStepBytes); - const uint16_t dispmt_u_p1 = static_cast<uint16_t>(dispmt >> 16) & 0xffff; - const uint16_t dispmt_u_p2 = static_cast<uint16_t>(dispmt) & 0xffff; - snprintf( - out, out_sz, - " jsr 0x%x:l | %04x %04x %04x @%08x\n", - dispmt, instr, dispmt_u_p1, dispmt_u_p2, offset); - return 6; - } - return disasm_verbatim(out, out_sz, instr, offset, code); - case 2: // 4eba, Displacement - { - const int16_t dispmt = GetI16BE(code.buffer + offset + kInstructionSizeStepBytes); - const uint16_t dispmt_u = static_cast<uint16_t>(dispmt); - snprintf( - out, out_sz, - " jsr %%pc@(%d:w) | %04x %04x @%08x\n", - dispmt, instr, dispmt_u, offset); - return 4; - } - break; - case 3: // 4ebb - { - const uint16_t briefext = GetU16BE(code.buffer + offset + kInstructionSizeStepBytes); - const int m_0d_1a = (briefext >> 15) & 1; - const int xn2 = (briefext >> 12) & 7; - const int s_0w_1l = (briefext >> 11) & 1; - const int8_t dispmt = briefext & 0xff; - snprintf( - out, out_sz, - " jsr %%pc@(%d,%%%c%d:%c) | %04x %04x @%08x\n", - dispmt, m_0d_1a ? 'a' : 'd', xn2, s_0w_1l ? 'l' : 'w', instr, briefext, offset); - return 4; - } - break; - case 4: // 4ebc - case 5: // 4ebd - case 6: // 4ebe - return disasm_verbatim(out, out_sz, instr, offset, code); - } - break; - } - return disasm_verbatim(out, out_sz, instr, offset, code); -} - -static size_t disasm( - char *out, size_t out_sz, uint16_t instr, uint32_t offset, const DataBuffer & code) -{ - if ((instr & 0xfff0) == 0x4e70) { - return disasm_mfff0_v4e70(out, out_sz, instr, offset, code); - } else if ((instr & 0xffc0) == 0x4e80) { - return disasm_jsr(out, out_sz, instr, offset, code); - } - return disasm_verbatim(out, out_sz, instr, offset, code); -} - void DisasmNode::Disasm(const DataBuffer &code) { constexpr size_t kBufferSize = 100; @@ -237,7 +55,11 @@ void DisasmNode::Disasm(const DataBuffer &code) // We assume that no MMU and ROM is always starts with 0 assert(this->offset < code.occupied_size); const uint16_t instr = GetU16BE(code.buffer + this->offset); - this->size = disasm(asm_str, kBufferSize, instr, this->offset, code); + const size_t rendered_sz = m68k_disasm( + asm_str, kBufferSize, &this->size, instr, this->offset, code); + const size_t comment_rendered_sz = m68k_render_raw_data_comment( + asm_str + rendered_sz, kBufferSize - rendered_sz, this->offset, this->size, code); + (void) comment_rendered_sz; } DisasmNode::~DisasmNode() @@ -315,6 +137,7 @@ static void RenderDisassembly(FILE *output, const DisasmMap &disasm_map, const D if (node) { assert(node->asm_string); fputs(node->asm_string, output); + fputc('\n', output); i += node->size; } else { fprintf(output, " .short 0x%02x%02x\n", code.buffer[i], code.buffer[i + 1]); @@ -34,10 +34,9 @@ run_test_simple() { hexdump -Cv ${file_orig_bin} | head -n1 echo ${file_as_bin} hexdump -Cv ${file_as_bin} | head -n1 - break; else echo "OK" - cat ${file_asm} + #cat ${file_asm} fi } |