diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index 896a853..a8c5db6 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -6,12 +6,14 @@ SET(CMAKE_EXE_LINKER_FLAGS "-framework Carbon") add_definitions(-I ${CMAKE_SOURCE_DIR}/) -add_executable(mpw loader.cpp) +add_executable(mpw loader.cpp debugger.cpp) target_link_libraries(mpw CPU_LIB) +target_link_libraries(mpw DEBUGGER_LIB) target_link_libraries(mpw TOOLBOX_LIB) target_link_libraries(mpw MPW_LIB) target_link_libraries(mpw MPLITE_LIB) target_link_libraries(mpw MACOS_LIB) +set_target_properties(mpw PROPERTIES LINK_FLAGS "-ledit") add_executable(disasm disasm.cpp) diff --git a/bin/debugger.cpp b/bin/debugger.cpp new file mode 100644 index 0000000..fb5eb59 --- /dev/null +++ b/bin/debugger.cpp @@ -0,0 +1,172 @@ + +#include +#include +#include +#include +#include +#include + +#include + + +#include "loader.h" + +#include + + + +bool ParseLine(const char *iter, Command *command); +extern "C" { + + uint32_t debuggerReadLong(uint32_t address) + { + uint32_t tmp = 0; + for (unsigned i = 0; i < 4; ++i) + { + if (address < Flags.memorySize) + tmp = (tmp << 8) + Flags.memory[address++]; + } + + return tmp; + } + +} + +void DebugHelp(const Command &cmd) +{ + printf("help\n"); + printf("break expression\n"); + printf("step"); + printf("continue"); + printf("\n"); + printf("print expression\n"); + printf("list expression\n"); + printf("dump expression\n"); + printf("register=expression\n"); + printf("\n"); + printf("registers: a0-7, d0-7, pc, sp, fp, csr\n"); + printf("\n"); +} + + +void DebugPrint(const Command &cmd) +{ + for (unsigned i = 0; i < cmd.argc; ++i) + { + uint32_t data = cmd.argv[i]; + printf("$%08x %12u", data, data); + if (data & 0x80000000) + printf(" %12d", (int32_t)data); + if ((data & 0xffff8000) == 0x8000) + printf(" %6d", (int16_t)data); + + printf("\n"); + } +} + +void hexdump(const uint8_t *data, ssize_t size, uint32_t address = 0) +{ +const char *HexMap = "0123456789abcdef"; + + char buffer1[16 * 3 + 1 + 1]; + char buffer2[16 + 1]; + ssize_t offset = 0; + unsigned i, j; + + + while(size > 0) + { + std::memset(buffer1, ' ', sizeof(buffer1)); + std::memset(buffer2, ' ', sizeof(buffer2)); + + unsigned linelen = (unsigned)std::min(size, (ssize_t)16); + + + for (i = 0, j = 0; i < linelen; i++) + { + unsigned x = data[i]; + buffer1[j++] = HexMap[x >> 4]; + buffer1[j++] = HexMap[x & 0x0f]; + j++; + if (i == 7) j++; + + // isascii not part of std:: and may be a macro. + buffer2[i] = isascii(x) && std::isprint(x) ? x : '.'; + + } + + buffer1[sizeof(buffer1)-1] = 0; + buffer2[sizeof(buffer2)-1] = 0; + + + std::printf("%08x:\t%s\t%s\n", address + (unsigned)offset, buffer1, buffer2); + offset += 16; + data += 16; + size -= 16; + } + std::printf("\n"); +} + +void DebugDump(const Command &cmd) +{ + // TODO -- if no address, use previous address. + if (cmd.argc == 1) + { + uint32_t start = cmd.argv[0]; + if (start > Flags.memorySize) return; + + uint32_t end = std::min(start + 512, Flags.memorySize); + ssize_t size = end - start; + + hexdump(Flags.memory + start, size, start); + + } +} + +void DebugShell() +{ + char *cp; + + add_history("!Andy, it still has history!"); + for(;;) + { + cp = readline("] "); + if (!cp) + { + printf("\n"); + break; // prompt for exit? + } + // parse the command... + const char *iter = cp; + while (*iter && isspace(*iter)) ++iter; + + if (*iter) + { + Command cmd; + std::memset(&cmd, 0, sizeof(cmd)); + if (ParseLine(iter, &cmd)) + { + switch(cmd.action) + { + case Print: + DebugPrint(cmd); + break; + + case Dump: + DebugDump(cmd); + break; + + default: + DebugHelp(cmd); + break; + } + } + + // todo -- don't add if same as previous command. + add_history(cp); + } + free(cp); + } + +} + diff --git a/bin/loader.cpp b/bin/loader.cpp index fea27d4..fc5d2b1 100644 --- a/bin/loader.cpp +++ b/bin/loader.cpp @@ -1,6 +1,7 @@ // clang++ -c -std=c++11 -stdlib=libc++ -Wno-deprecated-declarations loader.cpp #include +#include #include #include #include @@ -27,21 +28,9 @@ #include #include -struct { - uint32_t ram; - uint32_t stack; - uint32_t machine; - - bool traceCPU; - bool traceMacsbug; - bool traceGlobals; - bool traceToolBox; - bool traceMPW; - - bool memoryStats; - -} Flags = { 16 * 1024 * 1024, 8 * 1024, 68030, false, false, false, false, false, false}; +#include "loader.h" +Settings Flags; const uint32_t kGlobalSize = 0x10000; // retained to make debugging easier. @@ -113,6 +102,8 @@ void WriteLong(void *data, uint32_t offset, uint32_t value) ((uint8_t *)data)[offset++] = value; } + + uint32_t load(const char *file) { @@ -280,10 +271,41 @@ void GlobalInit() // so put stack at top of memory? // 0x0130 -- ApplLimit - memoryWriteLong(Flags.ram - 1, MacOS::ApplLimit); + memoryWriteLong(Flags.memorySize - 1, MacOS::ApplLimit); } +void CreateStack() +{ + // allocate stack, set A7... + + uint32_t address; + uint16_t error; + + Flags.stackSize = (Flags.stackSize + 3) & ~0x03; + + error = MM::Native::NewPtr(Flags.stackSize, true, address); + if (error) + { + fprintf(stderr, "Unable to allocate stack (%08x bytes)\n", Flags.stackSize); + exit(EX_CONFIG); + } + + + Flags.stackRange.first = address; + Flags.stackRange.second = address + Flags.stackSize; + + // TODO -- is there a global for the max (min) stack pointer? + + // address grows down + // -4 is for the return address. + cpuSetAReg(7, Flags.stackRange.second - 4); + // return address. + memoryWriteLong(MacOS::MinusOne, Flags.stackRange.second - 4); // MinusOne Global -- 0xffff ffff +} + + + void LogToolBox(uint32_t pc, uint16_t trap) { const char *name; @@ -509,6 +531,62 @@ std::string find_exe(const std::string &name) } +void MainLoop() +{ + #if 0 + auto begin_emu_time = std::chrono::high_resolution_clock::now(); + fprintf(stderr, "Begin Emulation Time: %20lld\n", (begin_emu_time - start_time).count()); + #endif + + + uint64_t cycles = 0; + for (;;) + { + uint32_t pc = cpuGetPC(); + uint32_t sp = cpuGetAReg(7); + + if (pc == 0x00000000) + { + fprintf(stderr, "Exiting - PC = 0\n"); + exit(EX_SOFTWARE); + } + + if (sp < Flags.stackRange.first) + { + fprintf(stderr, "Stack overflow error - please increase the stack size (--stack=size)\n"); + fprintf(stderr, "Current stack size is 0x%06x\n", Flags.stackSize); + exit(EX_SOFTWARE); + } + + if (sp > Flags.stackRange.second) + { + fprintf(stderr, "Stack underflow error\n"); + exit(EX_SOFTWARE); + } + + + if (cpuGetStop()) break; // will this also be set by an interrupt? + + + #ifndef CPU_INSTRUCTION_LOGGING + if (Flags.traceCPU || Flags.traceMacsbug) + { + InstructionLogger(); + } + #endif + + cycles += cpuExecuteInstruction(); + } + + #if 0 + auto end_emu_time = std::chrono::high_resolution_clock::now(); + fprintf(stderr, " End Emulation Time: %20lld\n", (end_emu_time - start_time).count()); + fprintf(stderr, " Cycles: %20lld\n", cycles); + #endif + + +} + int main(int argc, char **argv) { // getopt... @@ -520,6 +598,7 @@ int main(int argc, char **argv) kTraceGlobals, kTraceToolBox, kTraceMPW, + kDebugger, kMemoryStats, }; static struct option LongOpts[] = @@ -534,6 +613,9 @@ int main(int argc, char **argv) { "trace-tools", no_argument, NULL, kTraceToolBox }, { "trace-mpw", no_argument, NULL, kTraceMPW }, + { "debug", no_argument, NULL, kDebugger }, + { "debugger", no_argument, NULL, kDebugger }, + { "memory-stats", no_argument, NULL, kMemoryStats }, { "help", no_argument, NULL, 'h' }, @@ -572,18 +654,22 @@ int main(int argc, char **argv) Flags.memoryStats = true; break; + case kDebugger: + Flags.debugger = true; + break; + case 'm': if (!parse_number(optarg, &Flags.machine)) exit(EX_CONFIG); break; case 'r': - if (!parse_number(optarg, &Flags.ram)) + if (!parse_number(optarg, &Flags.memorySize)) exit(EX_CONFIG); break; case 's': - if (!parse_number(optarg, &Flags.stack)) + if (!parse_number(optarg, &Flags.stackSize)) exit(EX_CONFIG); break; @@ -615,6 +701,19 @@ int main(int argc, char **argv) exit(EX_USAGE); } + if (Flags.stackSize < 0x100) + { + fprintf(stderr, "Invalid stack size\n"); + exit(EX_CONFIG); + } + + if (Flags.memorySize < 0x200) + { + fprintf(stderr, "Invalid ram size\n"); + exit(EX_CONFIG); + } + + std::string command(argv[0]); // InitMPW updates argv... command = find_exe(command); @@ -628,9 +727,9 @@ int main(int argc, char **argv) argv[0] = ::strdup(command.c_str()); // hmm.. could setenv(mpw_command) instead. - - Memory = new uint8_t[Flags.ram]; - MemorySize = Flags.ram; + // move to CreateRam() + Memory = Flags.memory = new uint8_t[Flags.memorySize]; + MemorySize = Flags.memorySize; /// ahhh... need to set PC after memory. @@ -649,39 +748,7 @@ int main(int argc, char **argv) cpuSetModel(3,0); - - if (!Flags.stack) - { - fprintf(stderr, "Invalid stack size\n"); - exit(EX_CONFIG); - } - - std::pair StackRange; - // allocate stack, set A7... - { - uint32_t address; - uint16_t error; - - Flags.stack = (Flags.stack + 3) & ~0x03; - - error = MM::Native::NewPtr(Flags.stack, true, address); - if (error) - { - fprintf(stderr, "Unable to allocate stack (%08x bytes)\n", Flags.stack); - exit(EX_CONFIG); - } - - StackRange.first = address; - StackRange.second = address + Flags.stack; - - // TODO -- is there a global for the max (min) stack pointer? - - // address grows down - // -4 is for the return address. - cpuSetAReg(7, address + Flags.stack - 4); - // return address. - memoryWriteLong(MacOS::MinusOne, StackRange.second - 4); // MinusOne Global -- 0xffff ffff - } + CreateStack(); uint32_t address = load(command.c_str()); @@ -712,58 +779,11 @@ int main(int argc, char **argv) cpuInitializeFromNewPC(address); - #if 0 - auto begin_emu_time = std::chrono::high_resolution_clock::now(); - fprintf(stderr, "Begin Emulation Time: %20lld\n", (begin_emu_time - start_time).count()); - #endif - uint64_t cycles = 0; - for (;;) - { - uint32_t pc = cpuGetPC(); - uint32_t sp = cpuGetAReg(7); - - if (pc == 0x00000000) - { - fprintf(stderr, "Exiting - PC = 0\n"); - exit(EX_SOFTWARE); - } - - if (sp < StackRange.first) - { - fprintf(stderr, "Stack overflow error - please increase the stack size (--stack=size)\n"); - fprintf(stderr, "Current stack size is 0x%06x\n", Flags.stack); - exit(EX_SOFTWARE); - } - - if (sp > StackRange.second) - { - fprintf(stderr, "Stack underflow error\n"); - exit(EX_SOFTWARE); - } + if (Flags.debugger) DebugShell(); + else MainLoop(); - if (cpuGetStop()) break; // will this also be set by an interrupt? - - - - #ifndef CPU_INSTRUCTION_LOGGING - if (Flags.traceCPU || Flags.traceMacsbug) - { - InstructionLogger(); - } - #endif - - - - cycles += cpuExecuteInstruction(); - } - - #if 0 - auto end_emu_time = std::chrono::high_resolution_clock::now(); - fprintf(stderr, " End Emulation Time: %20lld\n", (end_emu_time - start_time).count()); - fprintf(stderr, " Cycles: %20lld\n", cycles); - #endif if (Flags.memoryStats) { diff --git a/bin/loader.h b/bin/loader.h new file mode 100644 index 0000000..7f61033 --- /dev/null +++ b/bin/loader.h @@ -0,0 +1,41 @@ +#ifndef __mpw_loader__ +#define __mpw_loader__ + +#include + +struct Settings { + Settings() {} + + // command-line settings. + + uint32_t memorySize = 16 * 1024 * 1024; + uint32_t stackSize = 16 * 1024; + uint32_t machine = 68030; + + bool traceCPU = false; + bool traceMacsbug = false; + bool traceGlobals = false; + bool traceToolBox = false; + bool traceMPW = false; + + bool debugger = false; + + bool memoryStats = false; + + + // updated later. + std::pair stackRange = {0, 0}; + uint8_t *memory = nullptr; + + uint64_t cycles = 0; + + const uint32_t kGlobalSize = 0x10000; +}; + + +extern Settings Flags; + +void DebugShell(); + + +#endif