mirror of
https://github.com/dingusdev/dingusppc.git
synced 2024-05-28 17:41:40 +00:00
Merging the 68k debugger from another branch
This commit is contained in:
commit
0c202b0c2d
|
@ -16,10 +16,14 @@ if (UNIX AND NOT APPLE)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(CAPSTONE REQUIRED capstone>=4.0.1)
|
||||
include_directories(${CAPSTONE_INCLUDE_DIRS})
|
||||
link_directories(${CAPSTONE_LIBRARY_DIRS})
|
||||
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/cpu/ppc/")
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/debugger/")
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/devices/")
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/execution")
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/machines/")
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/thirdparty/loguru/")
|
||||
|
||||
|
@ -36,8 +40,6 @@ set(BUILD_TOOLS OFF CACHE BOOL "Build Cubeb tools")
|
|||
|
||||
add_subdirectory(thirdparty/cubeb EXCLUDE_FROM_ALL)
|
||||
|
||||
set(CLI11_ROOT ${PROJECT_SOURCE_DIR}/thirdparty/CLI11)
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}/devices"
|
||||
"${PROJECT_SOURCE_DIR}/cpu/ppc"
|
||||
"${PROJECT_SOURCE_DIR}/debugger"
|
||||
|
@ -58,7 +60,6 @@ file(GLOB TEST_SOURCES "${PROJECT_SOURCE_DIR}/cpu/ppc/test/*.cpp")
|
|||
add_executable(dingusppc ${SOURCES} $<TARGET_OBJECTS:debugger>
|
||||
$<TARGET_OBJECTS:cpu_ppc>
|
||||
$<TARGET_OBJECTS:devices>
|
||||
$<TARGET_OBJECTS:execution>
|
||||
$<TARGET_OBJECTS:machines>
|
||||
$<TARGET_OBJECTS:loguru>)
|
||||
|
||||
|
@ -68,15 +69,13 @@ target_link_libraries(dingusppc "${PROJECT_SOURCE_DIR}/thirdparty/SDL2/lib/x64/S
|
|||
cubeb)
|
||||
else()
|
||||
#target_link_libraries(dingusppc libsoundio_static ${LIBSOUNDIO_LIBS} ${SDL2_LIBRARIES})
|
||||
target_link_libraries(dingusppc cubeb ${SDL2_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_include_directories(dingusppc PRIVATE ${CLI11_ROOT})
|
||||
target_link_libraries(dingusppc cubeb ${SDL2_LIBRARIES} ${CAPSTONE_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
|
||||
add_executable(testppc ${TEST_SOURCES} $<TARGET_OBJECTS:debugger>
|
||||
$<TARGET_OBJECTS:cpu_ppc>
|
||||
$<TARGET_OBJECTS:devices>
|
||||
$<TARGET_OBJECTS:execution>
|
||||
$<TARGET_OBJECTS:machines>
|
||||
$<TARGET_OBJECTS:loguru>)
|
||||
|
||||
|
@ -86,19 +85,9 @@ target_link_libraries(testppc "${PROJECT_SOURCE_DIR}/thirdparty/SDL2/lib/x64/SDL
|
|||
cubeb)
|
||||
else()
|
||||
#target_link_libraries(testppc libsoundio_static ${LIBSOUNDIO_LIBS} ${SDL2_LIBRARIES})
|
||||
target_link_libraries(testppc cubeb ${SDL2_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
target_link_libraries(testppc cubeb ${SDL2_LIBRARIES} ${CAPSTONE_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
|
||||
file(GLOB BENCH_SOURCES "${PROJECT_SOURCE_DIR}/benchmark/*.cpp")
|
||||
add_executable(bench1 ${BENCH_SOURCES} $<TARGET_OBJECTS:debugger>
|
||||
$<TARGET_OBJECTS:cpu_ppc>
|
||||
$<TARGET_OBJECTS:devices>
|
||||
$<TARGET_OBJECTS:execution>
|
||||
$<TARGET_OBJECTS:machines>
|
||||
$<TARGET_OBJECTS:loguru>)
|
||||
|
||||
target_link_libraries(bench1 cubeb ${SDL2_LIBRARIES} ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
add_custom_command(
|
||||
TARGET testppc POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
|
|
|
@ -554,6 +554,7 @@ extern void ppc_main_opcode(void);
|
|||
extern void ppc_exec(void);
|
||||
extern void ppc_exec_single(void);
|
||||
extern void ppc_exec_until(uint32_t goal_addr);
|
||||
extern void ppc_exec_dbg(uint32_t start_addr, uint32_t size);
|
||||
|
||||
/* debugging support API */
|
||||
void print_gprs(void); /* print content of the general purpose registers */
|
||||
|
|
|
@ -86,9 +86,17 @@ static PPCOpcode OpcodeGrabber[] = {
|
|||
ppc_illegalop, ppc_illegalop, ppc_illegalop, ppc_opcode63};
|
||||
|
||||
/** Lookup tables for branch instructions. */
|
||||
static PPCOpcode SubOpcode16Grabber[] = {ppc_bc, ppc_bcl, ppc_bca, ppc_bcla};
|
||||
static PPCOpcode SubOpcode16Grabber[] = {
|
||||
dppc_interpreter::ppc_bc,
|
||||
dppc_interpreter::ppc_bcl,
|
||||
dppc_interpreter::ppc_bca,
|
||||
dppc_interpreter::ppc_bcla};
|
||||
|
||||
static PPCOpcode SubOpcode18Grabber[] = {ppc_b, ppc_bl, ppc_ba, ppc_bla};
|
||||
static PPCOpcode SubOpcode18Grabber[] = {
|
||||
dppc_interpreter::ppc_b,
|
||||
dppc_interpreter::ppc_bl,
|
||||
dppc_interpreter::ppc_ba,
|
||||
dppc_interpreter::ppc_bla};
|
||||
|
||||
/** Instructions decoding tables for integer,
|
||||
single floating-point, and double-floating point ops respectively */
|
||||
|
@ -352,7 +360,7 @@ void ppc_exec_single()
|
|||
}
|
||||
|
||||
/** Execute PPC code until goal_addr is reached. */
|
||||
void ppc_exec_until(uint32_t goal_addr)
|
||||
void ppc_exec_until(volatile uint32_t goal_addr)
|
||||
{
|
||||
uint32_t bb_start_la, page_start, delta;
|
||||
uint8_t* pc_real;
|
||||
|
@ -411,6 +419,68 @@ again:
|
|||
}
|
||||
}
|
||||
|
||||
/** Execute PPC code until control is reached the specified region. */
|
||||
void ppc_exec_dbg(volatile uint32_t start_addr, volatile uint32_t size)
|
||||
{
|
||||
uint32_t bb_start_la, page_start, delta;
|
||||
uint8_t* pc_real;
|
||||
|
||||
/* start new basic block */
|
||||
glob_bb_start_la = bb_start_la = ppc_state.pc;
|
||||
bb_kind = BB_end_kind::BB_NONE;
|
||||
|
||||
if (setjmp(exc_env)) {
|
||||
/* reaching here means we got a low-level exception */
|
||||
#ifdef NEW_TBR_UPDATE_ALGO
|
||||
cycles_count += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
|
||||
UPDATE_TBR_DEC
|
||||
#else
|
||||
timebase_counter += ((ppc_state.pc - glob_bb_start_la) >> 2) + 1;
|
||||
#endif
|
||||
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
ppc_state.pc = bb_start_la;
|
||||
bb_kind = BB_end_kind::BB_NONE;
|
||||
//printf("DBG Exec: got exception, continue at %X\n", ppc_state.pc);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* initial MMU translation for the current code page. */
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
|
||||
/* set current code page limits */
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
|
||||
again:
|
||||
while (ppc_state.pc < start_addr || ppc_state.pc >= start_addr + size) {
|
||||
ppc_main_opcode();
|
||||
if (bb_kind != BB_end_kind::BB_NONE) {
|
||||
#ifdef NEW_TBR_UPDATE_ALGO
|
||||
cycles_count += ((ppc_state.pc - bb_start_la) >> 2) + 1;
|
||||
UPDATE_TBR_DEC
|
||||
#else
|
||||
timebase_counter += ((ppc_state.pc - bb_start_la) >> 2) + 1;
|
||||
#endif
|
||||
glob_bb_start_la = bb_start_la = ppc_next_instruction_address;
|
||||
if ((ppc_next_instruction_address & 0xFFFFF000) != page_start) {
|
||||
page_start = bb_start_la & 0xFFFFF000;
|
||||
pc_real = quickinstruction_translate(bb_start_la);
|
||||
} else {
|
||||
pc_real += (int)bb_start_la - (int)ppc_state.pc;
|
||||
ppc_set_cur_instruction(pc_real);
|
||||
}
|
||||
ppc_state.pc = bb_start_la;
|
||||
bb_kind = BB_end_kind::BB_NONE;
|
||||
//printf("DBG Exec: new basic block at %X, start_addr=%X\n", ppc_state.pc, start_addr);
|
||||
} else {
|
||||
ppc_state.pc += 4;
|
||||
pc_real += 4;
|
||||
ppc_set_cur_instruction(pc_real);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint64_t instr_count, old_instr_count;
|
||||
|
||||
|
|
|
@ -19,9 +19,6 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../cpu/ppc/ppcdisasm.h"
|
||||
#include "../cpu/ppc/ppcemu.h"
|
||||
#include "../cpu/ppc/ppcmmu.h"
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
@ -30,6 +27,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <thirdparty/loguru/loguru.hpp>
|
||||
#include <capstone/capstone.h>
|
||||
#include "../cpu/ppc/ppcdisasm.h"
|
||||
#include "../cpu/ppc/ppcemu.h"
|
||||
#include "../cpu/ppc/ppcmmu.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
@ -71,6 +72,9 @@ static void show_help() {
|
|||
cout << " disas N,X -- disassemble N instructions starting at address X" << endl;
|
||||
cout << " X can be any number or a known register name" << endl;
|
||||
cout << " disas with no arguments defaults to disas 1,pc" << endl;
|
||||
cout << " context X -- switch to the debugging context X." << endl;
|
||||
cout << " X can be either 'ppc' (default) or '68k'" << endl;
|
||||
cout << " Use 68k for debugging emulated 68k code only." << endl;
|
||||
cout << " quit -- quit the debugger" << endl << endl;
|
||||
cout << "Pressing ENTER will repeat last command." << endl;
|
||||
}
|
||||
|
@ -88,6 +92,113 @@ static void disasm(uint32_t count, uint32_t address) {
|
|||
}
|
||||
}
|
||||
|
||||
static void disasm_68k(uint32_t count, uint32_t address) {
|
||||
csh cs_handle;
|
||||
uint8_t code[10];
|
||||
size_t code_size;
|
||||
uint64_t dis_addr;
|
||||
|
||||
if (cs_open(CS_ARCH_M68K, CS_MODE_M68K_040, &cs_handle) != CS_ERR_OK) {
|
||||
cout << "Capstone initialization error" << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
cs_insn* insn = cs_malloc(cs_handle);
|
||||
|
||||
for (; count > 0; count--) {
|
||||
/* prefetch opcode bytes (a 68k instruction can occupy 2...10 bytes) */
|
||||
for (int i = 0; i < sizeof(code); i++) {
|
||||
code[i] = mem_read_dbg(address + i, 1);
|
||||
}
|
||||
|
||||
const uint8_t *code_ptr = code;
|
||||
code_size = sizeof(code);
|
||||
dis_addr = address;
|
||||
|
||||
if (cs_disasm_iter(cs_handle, &code_ptr, &code_size, &dis_addr, insn)) {
|
||||
cout << uppercase << hex << insn->address << " ";
|
||||
cout << setfill(' ');
|
||||
cout << setw(10) << left << insn->mnemonic << insn->op_str << endl;
|
||||
address = dis_addr;
|
||||
} else {
|
||||
cout << "DS.W " << hex << ((code[0] << 8) | code[1]) << endl;
|
||||
address += 2;
|
||||
}
|
||||
}
|
||||
|
||||
cs_free(insn, 1);
|
||||
cs_close(&cs_handle);
|
||||
}
|
||||
|
||||
/* emulator opcode table size --> 512 KB */
|
||||
#define EMU_68K_TABLE_SIZE 0x80000
|
||||
|
||||
/** Execute one emulated 68k instruction. */
|
||||
void exec_single_68k()
|
||||
{
|
||||
string reg;
|
||||
uint32_t emu_table_virt, cur_68k_pc, cur_instr_tab_entry, ppc_pc;
|
||||
|
||||
/* PPC r24 contains 68k PC advanced by two bytes
|
||||
as part of instruction prefetching */
|
||||
reg = "R24";
|
||||
cur_68k_pc = get_reg(reg) - 2;
|
||||
|
||||
/* PPC r29 contains base address of the emulator opcode table */
|
||||
reg = "R29";
|
||||
emu_table_virt = get_reg(reg) & 0xFFF80000;
|
||||
|
||||
/* calculate address of the current opcode table entry as follows:
|
||||
get_word(68k_PC) * entry_size + table_base */
|
||||
cur_instr_tab_entry = mem_grab_word(cur_68k_pc) * 8 + emu_table_virt;
|
||||
|
||||
/* grab the PPC PC too */
|
||||
reg = "PC";
|
||||
ppc_pc = get_reg(reg);
|
||||
|
||||
//printf("cur_instr_tab_entry = %X\n", cur_instr_tab_entry);
|
||||
|
||||
/* because the first two PPC instructions for each emulated 68k once
|
||||
are resided in the emulator opcode table, we need to execute them
|
||||
one by one until the execution goes outside the opcode table. */
|
||||
while (ppc_pc >= cur_instr_tab_entry && ppc_pc < cur_instr_tab_entry + 8) {
|
||||
ppc_exec_single();
|
||||
reg = "PC";
|
||||
ppc_pc = get_reg(reg);
|
||||
LOG_F(9, "Tracing within emulator table, PC = %X\n", ppc_pc);
|
||||
}
|
||||
|
||||
/* Getting here means we're outside the emualtor opcode table.
|
||||
Execute PPC code until we hit the opcode table again. */
|
||||
LOG_F(9, "Tracing outside the emulator table, PC = %X\n", ppc_pc);
|
||||
ppc_exec_dbg(emu_table_virt, EMU_68K_TABLE_SIZE - 1);
|
||||
}
|
||||
|
||||
/** Execute emulated 68k code until target_addr is reached. */
|
||||
void exec_until_68k(uint32_t target_addr)
|
||||
{
|
||||
string reg;
|
||||
uint32_t emu_table_virt, ppc_pc;
|
||||
|
||||
reg = "R29";
|
||||
emu_table_virt = get_reg(reg) & 0xFFF80000;
|
||||
|
||||
reg = "R24";
|
||||
while (target_addr != (get_reg(reg) - 2)) {
|
||||
reg = "PC";
|
||||
ppc_pc = get_reg(reg);
|
||||
|
||||
if (ppc_pc >= emu_table_virt && ppc_pc < (emu_table_virt + EMU_68K_TABLE_SIZE - 1)) {
|
||||
LOG_F(9, "Tracing within emulator table, PC = %X\n", ppc_pc);
|
||||
ppc_exec_single();
|
||||
} else {
|
||||
LOG_F(9, "Tracing outside the emulator table, PC = %X\n", ppc_pc);
|
||||
ppc_exec_dbg(emu_table_virt, EMU_68K_TABLE_SIZE - 1);
|
||||
}
|
||||
reg = "R24";
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_mem(string& params) {
|
||||
int cell_size, chars_per_line;
|
||||
bool is_char;
|
||||
|
@ -169,7 +280,8 @@ static void dump_mem(string& params) {
|
|||
cout << (char)val;
|
||||
chars_per_line += cell_size;
|
||||
} else {
|
||||
cout << setw(cell_size * 2) << setfill('0') << uppercase << hex << val << " ";
|
||||
cout << setw(cell_size * 2) << setfill('0') << right;
|
||||
cout << uppercase << hex << val << " ";
|
||||
chars_per_line += cell_size * 2 + 2;
|
||||
}
|
||||
}
|
||||
|
@ -181,18 +293,47 @@ static void dump_mem(string& params) {
|
|||
cout << endl << endl;
|
||||
}
|
||||
|
||||
void print_68k_regs()
|
||||
{
|
||||
int i;
|
||||
string reg;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
reg = "R" + to_string(i + 8);
|
||||
cout << "D" << dec << i << " : " << uppercase << hex << get_reg(reg) << endl;
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
reg = "R" + to_string(i + 16);
|
||||
cout << "A" << dec << i << " : " << uppercase << hex << get_reg(reg) << endl;
|
||||
}
|
||||
reg = "R1";
|
||||
cout << "A7 : " << uppercase << hex << get_reg(reg) << endl;
|
||||
|
||||
reg = "R24";
|
||||
cout << "PC: " << uppercase << hex << get_reg(reg) - 2 << endl;
|
||||
|
||||
reg = "R25";
|
||||
cout << "SR: " << uppercase << hex << ((get_reg(reg) & 0xFF) << 8) << endl;
|
||||
|
||||
reg = "R26";
|
||||
cout << "CCR: " << uppercase << hex << get_reg(reg) << endl;
|
||||
}
|
||||
|
||||
void enter_debugger() {
|
||||
string inp, cmd, addr_str, expr_str, reg_expr, last_cmd, reg_value_str, inst_string, inst_num_str;
|
||||
uint32_t addr, inst_grab;
|
||||
std::stringstream ss;
|
||||
int log_level;
|
||||
int log_level, context;
|
||||
size_t separator_pos;
|
||||
|
||||
context = 1; /* start with the PowerPC context */
|
||||
|
||||
cout << "Welcome to the DingusPPC command line debugger." << endl;
|
||||
cout << "Please enter a command or 'help'." << endl << endl;
|
||||
|
||||
while (1) {
|
||||
cout << "ppcdbg> ";
|
||||
cout << "dingusdbg> ";
|
||||
|
||||
/* reset string stream */
|
||||
ss.str("");
|
||||
|
@ -220,7 +361,11 @@ void enter_debugger() {
|
|||
}
|
||||
#endif
|
||||
else if (cmd == "regs") {
|
||||
print_gprs();
|
||||
if (context == 2) {
|
||||
print_68k_regs();
|
||||
} else {
|
||||
print_gprs();
|
||||
}
|
||||
} else if (cmd == "set") {
|
||||
ss >> expr_str;
|
||||
|
||||
|
@ -248,7 +393,11 @@ void enter_debugger() {
|
|||
cout << exc.what() << endl;
|
||||
}
|
||||
} else if (cmd == "step" || cmd == "si") {
|
||||
ppc_exec_single();
|
||||
if (context == 2) {
|
||||
exec_single_68k();
|
||||
} else {
|
||||
ppc_exec_single();
|
||||
}
|
||||
} else if (cmd == "next" || cmd == "ni") {
|
||||
addr_str = "PC";
|
||||
addr = get_reg(addr_str) + 4;
|
||||
|
@ -257,7 +406,11 @@ void enter_debugger() {
|
|||
ss >> addr_str;
|
||||
try {
|
||||
addr = str2addr(addr_str);
|
||||
ppc_exec_until(addr);
|
||||
if (context == 2) {
|
||||
exec_until_68k(addr);
|
||||
} else {
|
||||
ppc_exec_until(addr);
|
||||
}
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
}
|
||||
|
@ -278,27 +431,52 @@ void enter_debugger() {
|
|||
} catch (invalid_argument& exc) {
|
||||
try {
|
||||
/* number conversion failed, trying reg name */
|
||||
addr = get_reg(addr_str);
|
||||
if (context == 2 && (addr_str == "pc" || addr_str == "PC")) {
|
||||
addr_str = "R24";
|
||||
addr = get_reg(addr_str) - 2;
|
||||
} else {
|
||||
addr = get_reg(addr_str);
|
||||
}
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
try {
|
||||
disasm(inst_grab, addr);
|
||||
if (context == 2) {
|
||||
disasm_68k(inst_grab, addr);
|
||||
} else {
|
||||
disasm(inst_grab, addr);
|
||||
}
|
||||
} catch (invalid_argument& exc) {
|
||||
cout << exc.what() << endl;
|
||||
}
|
||||
} else {
|
||||
/* disas without arguments defaults to disas 1,pc */
|
||||
addr_str = "PC";
|
||||
addr = get_reg(addr_str);
|
||||
disasm(1, addr);
|
||||
if (context == 2) {
|
||||
addr_str = "R24";
|
||||
addr = get_reg(addr_str);
|
||||
disasm_68k(1, addr - 2);
|
||||
} else {
|
||||
addr_str = "PC";
|
||||
addr = get_reg(addr_str);
|
||||
disasm(1, addr);
|
||||
}
|
||||
}
|
||||
} else if (cmd == "dump") {
|
||||
expr_str = "";
|
||||
ss >> expr_str;
|
||||
dump_mem(expr_str);
|
||||
} else if (cmd == "context") {
|
||||
expr_str = "";
|
||||
ss >> expr_str;
|
||||
if (expr_str == "ppc" || expr_str == "PPC") {
|
||||
context = 1;
|
||||
} else if (expr_str == "68k" || expr_str == "68K") {
|
||||
context = 2;
|
||||
} else {
|
||||
cout << "Unknown debugging context: " << expr_str << endl;
|
||||
}
|
||||
} else {
|
||||
cout << "Unknown command: " << cmd << endl;
|
||||
continue;
|
||||
|
|
Loading…
Reference in New Issue
Block a user