/* SPDX-License-Identifier: Unlicense */ #include "m68k_debugging.hpp" #include "musashi-m68k/m68k.h" #include "bus.hpp" #include "utils.hpp" #include #include #include extern std::vector code_bkpts, read_bkpts, write_bkpts, access_bkpts; static inline m68k_register_t ConvertRegisterId(const M68KRegister register_id) { switch (register_id) { case M68KRegister::kD0: return M68K_REG_D0; case M68KRegister::kD1: return M68K_REG_D1; case M68KRegister::kD2: return M68K_REG_D2; case M68KRegister::kD3: return M68K_REG_D3; case M68KRegister::kD4: return M68K_REG_D4; case M68KRegister::kD5: return M68K_REG_D5; case M68KRegister::kD6: return M68K_REG_D6; case M68KRegister::kD7: return M68K_REG_D7; case M68KRegister::kA0: return M68K_REG_A0; case M68KRegister::kA1: return M68K_REG_A1; case M68KRegister::kA2: return M68K_REG_A2; case M68KRegister::kA3: return M68K_REG_A3; case M68KRegister::kA4: return M68K_REG_A4; case M68KRegister::kA5: return M68K_REG_A5; case M68KRegister::kA6: return M68K_REG_A6; case M68KRegister::kA7: return M68K_REG_A7; case M68KRegister::kPS: return M68K_REG_SR; case M68KRegister::kPC: return M68K_REG_PC; case M68KRegister::kFP0: case M68KRegister::kFPC: case M68KRegister::kFPS: case M68KRegister::kFPI: assert(!"Unsupported register_id"); break; } assert(!"Unknown register_id"); UNREACHABLE; } uint32_t M68KDebuggingControl::GetRegister(const M68KRegister register_id) const { return m68k_get_reg(nullptr, ConvertRegisterId(register_id)); } M68KCPUState M68KDebuggingControl::GetCPUState() const { return M68KCPUState{ static_cast(M68KRegister::kPC) + 1, { GetRegister(M68KRegister::kD0), GetRegister(M68KRegister::kD1), GetRegister(M68KRegister::kD2), GetRegister(M68KRegister::kD3), GetRegister(M68KRegister::kD4), GetRegister(M68KRegister::kD5), GetRegister(M68KRegister::kD6), GetRegister(M68KRegister::kD7), GetRegister(M68KRegister::kA0), GetRegister(M68KRegister::kA1), GetRegister(M68KRegister::kA2), GetRegister(M68KRegister::kA3), GetRegister(M68KRegister::kA4), GetRegister(M68KRegister::kA5), GetRegister(M68KRegister::kA6), GetRegister(M68KRegister::kA7), GetRegister(M68KRegister::kPS), GetRegister(M68KRegister::kPC), }, }; } void M68KDebuggingControl::SetRegister(const M68KRegister register_id, const uint32_t value) { return m68k_set_reg(ConvertRegisterId(register_id), value); } void M68KDebuggingControl::Reset() { m68k_pulse_reset(); } void M68KDebuggingControl::Continue() { // TODO abort(); } void M68KDebuggingControl::Pause() { // TODO abort(); } #define MASK_24(X) ((X) & 0x00ffffff) uint8_t M68KDebuggingControl::Read8(const uint32_t address) const { return static_cast(m68k_read_memory_8(MASK_24(address))); } uint16_t M68KDebuggingControl::Read16(const uint32_t address) const { return static_cast(m68k_read_memory_16(MASK_24(address))); } uint32_t M68KDebuggingControl::Read32(const uint32_t address) const { return static_cast(m68k_read_memory_32(MASK_24(address))); } void M68KDebuggingControl::Write8(const uint32_t address, const uint8_t value) { m68k_write_memory_8(address, value); } void M68KDebuggingControl::Write16(const uint32_t address, const uint16_t value) { m68k_write_memory_16(address, value); } void M68KDebuggingControl::Write32(const uint32_t address, const uint32_t value) { m68k_write_memory_32(address, value); } void M68KDebuggingControl::SetBreakpoint( const BreakpointType type, const uint32_t address_a, const uint32_t length) { const uint32_t address = MASK_24(address_a); switch (type) { case BreakpointType::kSoftwareBreakpoint: case BreakpointType::kHardwareBreakpoint: { for (size_t bi = 0; bi < code_bkpts.size(); bi++) { const auto& b = code_bkpts[bi]; if (b.offset == address && b.length == length) { return; } } code_bkpts.push_back(Breakpoint{address, length}); } break; case BreakpointType::kWriteWatchpoint: { for (size_t bi = 0; bi < write_bkpts.size(); bi++) { const auto& b = write_bkpts[bi]; if (b.offset == address && b.length == length) { return; } } write_bkpts.push_back(Breakpoint{address, length}); } break; case BreakpointType::kReadWatchpoint: { for (size_t bi = 0; bi < read_bkpts.size(); bi++) { const auto& b = read_bkpts[bi]; if (b.offset == address && b.length == length) { return; } } read_bkpts.push_back(Breakpoint{address, length}); } break; case BreakpointType::kAccessWatchpoint: { for (size_t bi = 0; bi < access_bkpts.size(); bi++) { const auto& b = access_bkpts[bi]; if (b.offset == address && b.length == length) { return; } } access_bkpts.push_back(Breakpoint{address, length}); } break; case BreakpointType::kUnsupported: { UNREACHABLE; } break; } } void M68KDebuggingControl::RemoveBreakpoint( const BreakpointType type, const uint32_t address_a, const uint32_t length) { const uint32_t address = MASK_24(address_a); switch (type) { case BreakpointType::kSoftwareBreakpoint: case BreakpointType::kHardwareBreakpoint: { for (size_t bi = 0; bi < code_bkpts.size(); bi++) { const auto& b = code_bkpts[bi]; if (b.offset == address && b.length == length) { code_bkpts.erase(code_bkpts.begin() + bi); break; } } } break; case BreakpointType::kWriteWatchpoint: { for (size_t bi = 0; bi < write_bkpts.size(); bi++) { const auto& b = write_bkpts[bi]; if (b.offset == address && b.length == length) { write_bkpts.erase(write_bkpts.begin() + bi); break; } } } break; case BreakpointType::kReadWatchpoint: { for (size_t bi = 0; bi < read_bkpts.size(); bi++) { const auto& b = read_bkpts[bi]; if (b.offset == address && b.length == length) { read_bkpts.erase(read_bkpts.begin() + bi); break; } } } break; case BreakpointType::kAccessWatchpoint: { for (size_t bi = 0; bi < access_bkpts.size(); bi++) { const auto& b = access_bkpts[bi]; if (b.offset == address && b.length == length) { access_bkpts.erase(access_bkpts.begin() + bi); break; } } } break; break; case BreakpointType::kUnsupported: { UNREACHABLE; } break; } }