diff --git a/Makefile b/Makefile index 426edb0c..c5241339 100644 --- a/Makefile +++ b/Makefile @@ -6,10 +6,13 @@ gb := gb gba := gba profile := accuracy -target := ethos +target := higan # target := loki -# options += debugger +ifeq ($(target),loki) + options += debugger +endif + # arch := x86 # console := true diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index 5c1bef06..ce39e369 100644 --- a/emulator/emulator.hpp +++ b/emulator/emulator.hpp @@ -3,7 +3,7 @@ namespace Emulator { static const char Name[] = "higan"; - static const char Version[] = "094.02"; + static const char Version[] = "094.04"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; static const char Website[] = "http://byuu.org/"; diff --git a/nall/Makefile b/nall/Makefile index bee3d22a..3d5cfcac 100644 --- a/nall/Makefile +++ b/nall/Makefile @@ -38,18 +38,18 @@ endif ifeq ($(compiler),) ifeq ($(platform),windows) compiler := g++ - flags := + flags := -fwrapv link := else ifeq ($(platform),macosx) compiler := clang++ - flags := -w -stdlib=libc++ + flags := -fwrapv -w -stdlib=libc++ link := -lc++ -lobjc else ifeq ($(platform),bsd) compiler := clang++ - flags := -w -I/usr/local/include + flags := -fwrapv -w -I/usr/local/include else compiler := g++ - flags := + flags := -fwrapv link := endif diff --git a/nall/platform.hpp b/nall/platform.hpp index e7bb9c6d..3d1ce6e3 100644 --- a/nall/platform.hpp +++ b/nall/platform.hpp @@ -73,13 +73,13 @@ namespace Math { //================ #if defined(__clang__) || defined(__GNUC__) - #define noinline __attribute__((noinline)) + #define neverinline __attribute__((noinline)) #define alwaysinline inline __attribute__((always_inline)) #elif defined(_MSC_VER) - #define noinline __declspec(noinline) + #define neverinline __declspec(noinline) #define alwaysinline inline __forceinline #else - #define noinline + #define neverinline #define alwaysinline inline #endif diff --git a/nall/utility.hpp b/nall/utility.hpp index 0447b94a..25609a7c 100644 --- a/nall/utility.hpp +++ b/nall/utility.hpp @@ -102,8 +102,7 @@ template struct optional { optional& operator=(const optional& source) { reset(); - valid = source.valid; - if(valid) operator=(source); + if(source) operator=(source()); return *this; } diff --git a/phoenix/cocoa/widget/console.cpp b/phoenix/cocoa/widget/console.cpp index 6a8823bc..2489c60c 100644 --- a/phoenix/cocoa/widget/console.cpp +++ b/phoenix/cocoa/widget/console.cpp @@ -17,6 +17,9 @@ void pConsole::print(string text) { void pConsole::reset() { } +void pConsole::setPrompt(string prompt) { +} + void pConsole::constructor() { @autoreleasepool { cocoaView = cocoaConsole = [[CocoaConsole alloc] initWith:console]; diff --git a/phoenix/cocoa/widget/console.hpp b/phoenix/cocoa/widget/console.hpp index c22596dd..1a852f68 100644 --- a/phoenix/cocoa/widget/console.hpp +++ b/phoenix/cocoa/widget/console.hpp @@ -13,6 +13,7 @@ struct pConsole : public pWidget { void print(string text); void reset(); + void setPrompt(string prompt); pConsole(Console& console) : pWidget(console), console(console) {} void constructor(); diff --git a/phoenix/core/core.cpp b/phoenix/core/core.cpp index 15190a3b..599d98c2 100644 --- a/phoenix/core/core.cpp +++ b/phoenix/core/core.cpp @@ -1221,10 +1221,19 @@ void Console::print(const string& text) { return p.print(text); } +string Console::prompt() const { + return state.prompt; +} + void Console::reset() { return p.reset(); } +void Console::setPrompt(const string& prompt) { + state.prompt = prompt; + return p.setPrompt(prompt); +} + Console::Console(): state(*new State), base_from_member(*new pConsole(*this)), diff --git a/phoenix/core/core.hpp b/phoenix/core/core.hpp index 68e516a9..715e6128 100644 --- a/phoenix/core/core.hpp +++ b/phoenix/core/core.hpp @@ -525,7 +525,9 @@ struct Console : private nall::base_from_member, Widget { template void print(Args&&... args) { print({args...}); } void print(const nall::string& text); + nall::string prompt() const; void reset(); + void setPrompt(const nall::string& prompt); Console(); ~Console(); diff --git a/phoenix/core/state.hpp b/phoenix/core/state.hpp index a650c84d..890c561e 100644 --- a/phoenix/core/state.hpp +++ b/phoenix/core/state.hpp @@ -125,6 +125,7 @@ struct ComboButton::State { }; struct Console::State { + string prompt; }; struct Frame::State { diff --git a/phoenix/gtk/platform.hpp b/phoenix/gtk/platform.hpp index b724e502..5c86bc11 100644 --- a/phoenix/gtk/platform.hpp +++ b/phoenix/gtk/platform.hpp @@ -348,9 +348,11 @@ struct pConsole : public pWidget { GtkWidget* subWidget; GtkTextBuffer* textBuffer; string command; + string previousPrompt; void print(string text); void reset(); + void setPrompt(string prompt); pConsole(Console& console) : pWidget(console), console(console) {} void constructor(); diff --git a/phoenix/gtk/widget/console.cpp b/phoenix/gtk/widget/console.cpp index 17503921..44d71436 100644 --- a/phoenix/gtk/widget/console.cpp +++ b/phoenix/gtk/widget/console.cpp @@ -5,14 +5,34 @@ static bool Console_keyPress(GtkWidget* widget, GdkEventKey* event, Console* sel } void pConsole::print(string text) { + //insert text before prompt and command, so as not to interrupt the current command + GtkTextIter iter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + gtk_text_iter_set_offset(&iter, gtk_text_iter_get_offset(&iter) - console.prompt().size() - command.size()); + gtk_text_buffer_insert(textBuffer, &iter, text, -1); seekCursorToEnd(); - gtk_text_buffer_insert_at_cursor(textBuffer, text, -1); - GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert"); - gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark); } void pConsole::reset() { - gtk_text_buffer_set_text(textBuffer, "", -1); + //flush history and command; draw prompt + command.reset(); + gtk_text_buffer_set_text(textBuffer, console.prompt(), -1); + seekCursorToEnd(); +} + +void pConsole::setPrompt(string prompt) { + //erase old prompt; insert new prompt in its place + GtkTextIter lhs, rhs, iter; + gtk_text_buffer_get_end_iter(textBuffer, &lhs); + gtk_text_buffer_get_end_iter(textBuffer, &rhs); + gtk_text_iter_set_offset(&lhs, gtk_text_iter_get_offset(&lhs) - previousPrompt.size() - command.size()); + gtk_text_iter_set_offset(&rhs, gtk_text_iter_get_offset(&rhs) - command.size()); + gtk_text_buffer_delete(textBuffer, &lhs, &rhs); + gtk_text_buffer_get_end_iter(textBuffer, &iter); + gtk_text_iter_set_offset(&iter, gtk_text_iter_get_offset(&iter) - command.size()); + gtk_text_buffer_insert(textBuffer, &iter, prompt, -1); + seekCursorToEnd(); + previousPrompt = prompt; } void pConsole::constructor() { @@ -51,27 +71,37 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { if(mask & (GDK_CONTROL_MASK | GDK_MOD1_MASK | GDK_SUPER_MASK)) return false; //allow actions such as Ctrl+C (copy) if(scancode == GDK_KEY_Return || scancode == GDK_KEY_KP_Enter) { - print("\n"); - if(console.onActivate) console.onActivate(command); + //add current prompt and command to history; print new prompt; execute command + GtkTextIter iter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + gtk_text_buffer_insert(textBuffer, &iter, string{"\n", console.prompt()}, -1); + string s = command; command.reset(); + if(console.onActivate) console.onActivate(s); + seekCursorToEnd(); return true; } if(scancode == GDK_KEY_BackSpace) { if(command.size()) { + //delete last character of command command.resize(command.size() - 1); GtkTextIter lhs, rhs; gtk_text_buffer_get_end_iter(textBuffer, &lhs); gtk_text_buffer_get_end_iter(textBuffer, &rhs); gtk_text_iter_set_offset(&lhs, gtk_text_iter_get_offset(&lhs) - 1); gtk_text_buffer_delete(textBuffer, &lhs, &rhs); - seekCursorToEnd(); } + seekCursorToEnd(); return true; } if(scancode >= 0x20 && scancode <= 0x7e) { - print({(char)scancode}); + //add character to end of command + GtkTextIter iter; + gtk_text_buffer_get_end_iter(textBuffer, &iter); + gtk_text_buffer_insert(textBuffer, &iter, string{(char)scancode}, -1); + seekCursorToEnd(); command.append((char)scancode); return true; } @@ -80,9 +110,12 @@ bool pConsole::keyPress(unsigned scancode, unsigned mask) { } void pConsole::seekCursorToEnd() { + //place cursor at end of text buffer; scroll text view to the cursor to ensure it is visible GtkTextIter iter; gtk_text_buffer_get_end_iter(textBuffer, &iter); gtk_text_buffer_place_cursor(textBuffer, &iter); + GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert"); + gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(subWidget), mark); } } diff --git a/phoenix/qt/platform.moc b/phoenix/qt/platform.moc index 63e93e95..6fd7d8aa 100644 --- a/phoenix/qt/platform.moc +++ b/phoenix/qt/platform.moc @@ -1,7 +1,7 @@ /**************************************************************************** ** Meta object code from reading C++ file 'platform.moc.hpp' ** -** Created: Mon Jan 20 01:11:54 2014 +** Created: Wed Jan 29 08:08:49 2014 ** by: The Qt Meta Object Compiler version 63 (Qt 4.8.2) ** ** WARNING! All changes made in this file will be lost! diff --git a/phoenix/qt/platform.moc.hpp b/phoenix/qt/platform.moc.hpp index 935da456..0c234594 100644 --- a/phoenix/qt/platform.moc.hpp +++ b/phoenix/qt/platform.moc.hpp @@ -432,6 +432,7 @@ public: void print(string text); void reset(); + void setPrompt(string prompt); pConsole(Console& console) : pWidget(console), console(console) {} void constructor(); diff --git a/phoenix/qt/widget/console.cpp b/phoenix/qt/widget/console.cpp index 2db6b7f5..ca1d9161 100644 --- a/phoenix/qt/widget/console.cpp +++ b/phoenix/qt/widget/console.cpp @@ -6,6 +6,9 @@ void pConsole::print(string text) { void pConsole::reset() { } +void pConsole::setPrompt(string prompt) { +} + void pConsole::constructor() { qtWidget = qtConsole = new QtConsole(*this); diff --git a/phoenix/reference/widget/console.cpp b/phoenix/reference/widget/console.cpp index 2df09f9e..0dd2a03f 100644 --- a/phoenix/reference/widget/console.cpp +++ b/phoenix/reference/widget/console.cpp @@ -6,6 +6,9 @@ void pConsole::print(string text) { void pConsole::reset() { } +void pConsole::setPrompt(string prompt) { +} + void pConsole::constructor() { } diff --git a/phoenix/reference/widget/console.hpp b/phoenix/reference/widget/console.hpp index dbb2692a..e0d4de57 100644 --- a/phoenix/reference/widget/console.hpp +++ b/phoenix/reference/widget/console.hpp @@ -5,6 +5,7 @@ struct pConsole : public pWidget { void print(string text); void reset(); + void setPrompt(string prompt); pConsole(Console& console) : pWidget(console), console(console) {} void constructor(); diff --git a/phoenix/windows/platform.hpp b/phoenix/windows/platform.hpp index 91dbd426..6d84d3ba 100644 --- a/phoenix/windows/platform.hpp +++ b/phoenix/windows/platform.hpp @@ -363,6 +363,7 @@ struct pConsole : public pWidget { void print(string text); void reset(); + void setPrompt(string prompt); pConsole(Console& console) : pWidget(console), console(console) {} void constructor(); diff --git a/phoenix/windows/widget/console.cpp b/phoenix/windows/widget/console.cpp index 74fe1b16..07971d4e 100644 --- a/phoenix/windows/widget/console.cpp +++ b/phoenix/windows/widget/console.cpp @@ -14,6 +14,9 @@ void pConsole::print(string text) { void pConsole::reset() { } +void pConsole::setPrompt(string prompt) { +} + void pConsole::constructor() { hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, L"EDIT", L"", diff --git a/processor/r65816/disassembler.cpp b/processor/r65816/disassembler.cpp index 38d05d34..f164ee19 100644 --- a/processor/r65816/disassembler.cpp +++ b/processor/r65816/disassembler.cpp @@ -102,7 +102,11 @@ uint32 R65816::decode(uint8 offset_type, uint32 addr) { return(r & 0xffffff); } -void R65816::disassemble_opcode(char* output, uint32 addr) { +void R65816::disassemble_opcode(char* output) { + return disassemble_opcode(output, regs.pc.d, regs.e, regs.p.m, regs.p.x); +} + +void R65816::disassemble_opcode(char* output, uint32 addr, bool e, bool m, bool x) { static reg24_t pc; char t[256]; char* s = output; @@ -123,8 +127,8 @@ void R65816::disassemble_opcode(char* output, uint32 addr) { #define op8 ((op0)) #define op16 ((op0) | (op1 << 8)) #define op24 ((op0) | (op1 << 8) | (op2 << 16)) - #define a8 (regs.e || regs.p.m) - #define x8 (regs.e || regs.p.x) + #define a8 (e || m) + #define x8 (e || x) switch(op) { case 0x00: sprintf(t, "brk #$%.2x ", op8); break; diff --git a/processor/r65816/disassembler.hpp b/processor/r65816/disassembler.hpp index a6732bd2..7b5d9c2c 100644 --- a/processor/r65816/disassembler.hpp +++ b/processor/r65816/disassembler.hpp @@ -22,7 +22,8 @@ enum : unsigned { OPTYPE_RELW, //relw }; -void disassemble_opcode(char* output, uint32 addr); +void disassemble_opcode(char* output); +void disassemble_opcode(char* output, uint32 addr, bool e, bool m, bool x); uint8 dreadb(uint32 addr); uint16 dreadw(uint32 addr); uint32 dreadl(uint32 addr); diff --git a/sfc/cpu/cpu.cpp b/sfc/cpu/cpu.cpp index 852755d3..1f01a9d0 100644 --- a/sfc/cpu/cpu.cpp +++ b/sfc/cpu/cpu.cpp @@ -88,7 +88,7 @@ void CPU::op_step() { debugger.op_exec(regs.pc.d); if(interface->tracer.open()) { char text[4096]; - disassemble_opcode(text, regs.pc.d); + disassemble_opcode(text); interface->tracer.print(text, "\n"); } diff --git a/sfc/cpu/cpu.hpp b/sfc/cpu/cpu.hpp index ed2c51f5..d4bb26f2 100644 --- a/sfc/cpu/cpu.hpp +++ b/sfc/cpu/cpu.hpp @@ -136,7 +136,7 @@ privileged: struct Debugger { hook op_exec; - hook op_read; + hook op_read; hook op_write; hook op_nmi; hook op_irq; diff --git a/sfc/cpu/memory/memory.cpp b/sfc/cpu/memory/memory.cpp index f47d3205..97aa6bb9 100644 --- a/sfc/cpu/memory/memory.cpp +++ b/sfc/cpu/memory/memory.cpp @@ -11,25 +11,23 @@ void CPU::op_io() { } uint8 CPU::op_read(uint32 addr) { - debugger.op_read(addr); - status.clock_count = speed(addr); dma_edge(); add_clocks(status.clock_count - 4); regs.mdr = bus.read(addr); add_clocks(4); alu_edge(); + debugger.op_read(addr, regs.mdr); return regs.mdr; } void CPU::op_write(uint32 addr, uint8 data) { - debugger.op_write(addr, data); - alu_edge(); status.clock_count = speed(addr); dma_edge(); add_clocks(status.clock_count); bus.write(addr, regs.mdr = data); + debugger.op_write(addr, regs.mdr); } unsigned CPU::speed(unsigned addr) const { diff --git a/target-ethos/Makefile b/target-higan/Makefile similarity index 96% rename from target-ethos/Makefile rename to target-higan/Makefile index ee3b6284..5fb0ce51 100644 --- a/target-ethos/Makefile +++ b/target-higan/Makefile @@ -8,7 +8,7 @@ include sfc/Makefile include gb/Makefile include gba/Makefile -ui_objects := ui-ethos ui-configuration ui-interface ui-utility +ui_objects := ui-higan ui-configuration ui-interface ui-utility ui_objects += ui-input ui-window ui-general ui-settings ui-tools ui_objects += phoenix ruby ui_objects += $(if $(call streq,$(platform),windows),resource) @@ -44,7 +44,7 @@ link += $(rubylink) objects := $(ui_objects) $(objects) objects := $(patsubst %,obj/%.o,$(objects)) -obj/ui-ethos.o: $(ui)/ethos.cpp $(call rwildcard,$(ui)/) +obj/ui-higan.o: $(ui)/higan.cpp $(call rwildcard,$(ui)/) obj/ui-configuration.o: $(ui)/configuration/configuration.cpp $(call rwildcard,$(ui)/) obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/) obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/) diff --git a/target-ethos/bootstrap.cpp b/target-higan/bootstrap.cpp similarity index 100% rename from target-ethos/bootstrap.cpp rename to target-higan/bootstrap.cpp diff --git a/target-ethos/configuration/configuration.cpp b/target-higan/configuration/configuration.cpp similarity index 99% rename from target-ethos/configuration/configuration.cpp rename to target-higan/configuration/configuration.cpp index 214a12b1..612f1bfc 100644 --- a/target-ethos/configuration/configuration.cpp +++ b/target-higan/configuration/configuration.cpp @@ -1,4 +1,4 @@ -#include "../ethos.hpp" +#include "../higan.hpp" ConfigurationSettings* config = nullptr; ConfigurationSettings::ConfigurationSettings() { diff --git a/target-ethos/configuration/configuration.hpp b/target-higan/configuration/configuration.hpp similarity index 100% rename from target-ethos/configuration/configuration.hpp rename to target-higan/configuration/configuration.hpp diff --git a/target-ethos/general/dip-switches.cpp b/target-higan/general/dip-switches.cpp similarity index 100% rename from target-ethos/general/dip-switches.cpp rename to target-higan/general/dip-switches.cpp diff --git a/target-ethos/general/dip-switches.hpp b/target-higan/general/dip-switches.hpp similarity index 100% rename from target-ethos/general/dip-switches.hpp rename to target-higan/general/dip-switches.hpp diff --git a/target-ethos/general/general.cpp b/target-higan/general/general.cpp similarity index 76% rename from target-ethos/general/general.cpp rename to target-higan/general/general.cpp index d4cb3101..fd34b8fa 100644 --- a/target-ethos/general/general.cpp +++ b/target-higan/general/general.cpp @@ -1,4 +1,4 @@ -#include "../ethos.hpp" +#include "../higan.hpp" #include "library.cpp" #include "presentation.cpp" #include "dip-switches.cpp" diff --git a/target-ethos/general/general.hpp b/target-higan/general/general.hpp similarity index 100% rename from target-ethos/general/general.hpp rename to target-higan/general/general.hpp diff --git a/target-ethos/general/library.cpp b/target-higan/general/library.cpp similarity index 100% rename from target-ethos/general/library.cpp rename to target-higan/general/library.cpp diff --git a/target-ethos/general/library.hpp b/target-higan/general/library.hpp similarity index 100% rename from target-ethos/general/library.hpp rename to target-higan/general/library.hpp diff --git a/target-ethos/general/presentation.cpp b/target-higan/general/presentation.cpp similarity index 100% rename from target-ethos/general/presentation.cpp rename to target-higan/general/presentation.cpp diff --git a/target-ethos/general/presentation.hpp b/target-higan/general/presentation.hpp similarity index 100% rename from target-ethos/general/presentation.hpp rename to target-higan/general/presentation.hpp diff --git a/target-ethos/ethos.cpp b/target-higan/higan.cpp similarity index 99% rename from target-ethos/ethos.cpp rename to target-higan/higan.cpp index c0d4fcd5..0d8fce73 100644 --- a/target-ethos/ethos.cpp +++ b/target-higan/higan.cpp @@ -1,4 +1,4 @@ -#include "ethos.hpp" +#include "higan.hpp" #include "bootstrap.cpp" #include "resource/resource.cpp" diff --git a/target-ethos/ethos.hpp b/target-higan/higan.hpp similarity index 100% rename from target-ethos/ethos.hpp rename to target-higan/higan.hpp diff --git a/target-ethos/input/hotkeys.cpp b/target-higan/input/hotkeys.cpp similarity index 100% rename from target-ethos/input/hotkeys.cpp rename to target-higan/input/hotkeys.cpp diff --git a/target-ethos/input/input.cpp b/target-higan/input/input.cpp similarity index 99% rename from target-ethos/input/input.cpp rename to target-higan/input/input.cpp index c6f1253a..bc0083c1 100644 --- a/target-ethos/input/input.cpp +++ b/target-higan/input/input.cpp @@ -1,4 +1,4 @@ -#include "../ethos.hpp" +#include "../higan.hpp" #include "hotkeys.cpp" InputManager* inputManager = nullptr; HID::Null hidNull; diff --git a/target-ethos/input/input.hpp b/target-higan/input/input.hpp similarity index 100% rename from target-ethos/input/input.hpp rename to target-higan/input/input.hpp diff --git a/target-ethos/interface/interface.cpp b/target-higan/interface/interface.cpp similarity index 99% rename from target-ethos/interface/interface.cpp rename to target-higan/interface/interface.cpp index 703f283e..c48e7f96 100644 --- a/target-ethos/interface/interface.cpp +++ b/target-higan/interface/interface.cpp @@ -1,4 +1,4 @@ -#include "../ethos.hpp" +#include "../higan.hpp" Interface* interface = nullptr; void Interface::loadRequest(unsigned id, string name, string type) { diff --git a/target-ethos/interface/interface.hpp b/target-higan/interface/interface.hpp similarity index 100% rename from target-ethos/interface/interface.hpp rename to target-higan/interface/interface.hpp diff --git a/target-ethos/resource.rc b/target-higan/resource.rc similarity index 100% rename from target-ethos/resource.rc rename to target-higan/resource.rc diff --git a/target-ethos/resource/advanced.png b/target-higan/resource/advanced.png similarity index 100% rename from target-ethos/resource/advanced.png rename to target-higan/resource/advanced.png diff --git a/target-ethos/resource/audio.png b/target-higan/resource/audio.png similarity index 100% rename from target-ethos/resource/audio.png rename to target-higan/resource/audio.png diff --git a/target-ethos/resource/cheat-editor.png b/target-higan/resource/cheat-editor.png similarity index 100% rename from target-ethos/resource/cheat-editor.png rename to target-higan/resource/cheat-editor.png diff --git a/target-ethos/resource/folder.png b/target-higan/resource/folder.png similarity index 100% rename from target-ethos/resource/folder.png rename to target-higan/resource/folder.png diff --git a/target-ethos/resource/game.png b/target-higan/resource/game.png similarity index 100% rename from target-ethos/resource/game.png rename to target-higan/resource/game.png diff --git a/target-ethos/resource/home.png b/target-higan/resource/home.png similarity index 100% rename from target-ethos/resource/home.png rename to target-higan/resource/home.png diff --git a/target-ethos/resource/hotkeys.png b/target-higan/resource/hotkeys.png similarity index 100% rename from target-ethos/resource/hotkeys.png rename to target-higan/resource/hotkeys.png diff --git a/target-ethos/resource/input.png b/target-higan/resource/input.png similarity index 100% rename from target-ethos/resource/input.png rename to target-higan/resource/input.png diff --git a/target-ethos/resource/resource.bml b/target-higan/resource/resource.bml similarity index 100% rename from target-ethos/resource/resource.bml rename to target-higan/resource/resource.bml diff --git a/target-ethos/resource/resource.cpp b/target-higan/resource/resource.cpp similarity index 100% rename from target-ethos/resource/resource.cpp rename to target-higan/resource/resource.cpp diff --git a/target-ethos/resource/resource.hpp b/target-higan/resource/resource.hpp similarity index 100% rename from target-ethos/resource/resource.hpp rename to target-higan/resource/resource.hpp diff --git a/target-ethos/resource/server.png b/target-higan/resource/server.png similarity index 100% rename from target-ethos/resource/server.png rename to target-higan/resource/server.png diff --git a/target-ethos/resource/state-manager.png b/target-higan/resource/state-manager.png similarity index 100% rename from target-ethos/resource/state-manager.png rename to target-higan/resource/state-manager.png diff --git a/target-ethos/resource/timing.png b/target-higan/resource/timing.png similarity index 100% rename from target-ethos/resource/timing.png rename to target-higan/resource/timing.png diff --git a/target-ethos/resource/unverified.png b/target-higan/resource/unverified.png similarity index 100% rename from target-ethos/resource/unverified.png rename to target-higan/resource/unverified.png diff --git a/target-ethos/resource/up.png b/target-higan/resource/up.png similarity index 100% rename from target-ethos/resource/up.png rename to target-higan/resource/up.png diff --git a/target-ethos/resource/video.png b/target-higan/resource/video.png similarity index 100% rename from target-ethos/resource/video.png rename to target-higan/resource/video.png diff --git a/target-ethos/settings/advanced.cpp b/target-higan/settings/advanced.cpp similarity index 100% rename from target-ethos/settings/advanced.cpp rename to target-higan/settings/advanced.cpp diff --git a/target-ethos/settings/advanced.hpp b/target-higan/settings/advanced.hpp similarity index 100% rename from target-ethos/settings/advanced.hpp rename to target-higan/settings/advanced.hpp diff --git a/target-ethos/settings/audio.cpp b/target-higan/settings/audio.cpp similarity index 100% rename from target-ethos/settings/audio.cpp rename to target-higan/settings/audio.cpp diff --git a/target-ethos/settings/audio.hpp b/target-higan/settings/audio.hpp similarity index 100% rename from target-ethos/settings/audio.hpp rename to target-higan/settings/audio.hpp diff --git a/target-ethos/settings/hotkey.cpp b/target-higan/settings/hotkey.cpp similarity index 100% rename from target-ethos/settings/hotkey.cpp rename to target-higan/settings/hotkey.cpp diff --git a/target-ethos/settings/hotkey.hpp b/target-higan/settings/hotkey.hpp similarity index 100% rename from target-ethos/settings/hotkey.hpp rename to target-higan/settings/hotkey.hpp diff --git a/target-ethos/settings/input.cpp b/target-higan/settings/input.cpp similarity index 100% rename from target-ethos/settings/input.cpp rename to target-higan/settings/input.cpp diff --git a/target-ethos/settings/input.hpp b/target-higan/settings/input.hpp similarity index 100% rename from target-ethos/settings/input.hpp rename to target-higan/settings/input.hpp diff --git a/target-ethos/settings/server.cpp b/target-higan/settings/server.cpp similarity index 100% rename from target-ethos/settings/server.cpp rename to target-higan/settings/server.cpp diff --git a/target-ethos/settings/server.hpp b/target-higan/settings/server.hpp similarity index 100% rename from target-ethos/settings/server.hpp rename to target-higan/settings/server.hpp diff --git a/target-ethos/settings/settings.cpp b/target-higan/settings/settings.cpp similarity index 98% rename from target-ethos/settings/settings.cpp rename to target-higan/settings/settings.cpp index daf77073..b9be5910 100644 --- a/target-ethos/settings/settings.cpp +++ b/target-higan/settings/settings.cpp @@ -1,4 +1,4 @@ -#include "../ethos.hpp" +#include "../higan.hpp" #include "video.cpp" #include "audio.cpp" #include "input.cpp" diff --git a/target-ethos/settings/settings.hpp b/target-higan/settings/settings.hpp similarity index 100% rename from target-ethos/settings/settings.hpp rename to target-higan/settings/settings.hpp diff --git a/target-ethos/settings/timing.cpp b/target-higan/settings/timing.cpp similarity index 100% rename from target-ethos/settings/timing.cpp rename to target-higan/settings/timing.cpp diff --git a/target-ethos/settings/timing.hpp b/target-higan/settings/timing.hpp similarity index 100% rename from target-ethos/settings/timing.hpp rename to target-higan/settings/timing.hpp diff --git a/target-ethos/settings/video.cpp b/target-higan/settings/video.cpp similarity index 100% rename from target-ethos/settings/video.cpp rename to target-higan/settings/video.cpp diff --git a/target-ethos/settings/video.hpp b/target-higan/settings/video.hpp similarity index 100% rename from target-ethos/settings/video.hpp rename to target-higan/settings/video.hpp diff --git a/target-ethos/tools/cheat-database.cpp b/target-higan/tools/cheat-database.cpp similarity index 100% rename from target-ethos/tools/cheat-database.cpp rename to target-higan/tools/cheat-database.cpp diff --git a/target-ethos/tools/cheat-database.hpp b/target-higan/tools/cheat-database.hpp similarity index 100% rename from target-ethos/tools/cheat-database.hpp rename to target-higan/tools/cheat-database.hpp diff --git a/target-ethos/tools/cheat-editor.cpp b/target-higan/tools/cheat-editor.cpp similarity index 100% rename from target-ethos/tools/cheat-editor.cpp rename to target-higan/tools/cheat-editor.cpp diff --git a/target-ethos/tools/cheat-editor.hpp b/target-higan/tools/cheat-editor.hpp similarity index 100% rename from target-ethos/tools/cheat-editor.hpp rename to target-higan/tools/cheat-editor.hpp diff --git a/target-ethos/tools/state-manager.cpp b/target-higan/tools/state-manager.cpp similarity index 100% rename from target-ethos/tools/state-manager.cpp rename to target-higan/tools/state-manager.cpp diff --git a/target-ethos/tools/state-manager.hpp b/target-higan/tools/state-manager.hpp similarity index 100% rename from target-ethos/tools/state-manager.hpp rename to target-higan/tools/state-manager.hpp diff --git a/target-ethos/tools/tools.cpp b/target-higan/tools/tools.cpp similarity index 96% rename from target-ethos/tools/tools.cpp rename to target-higan/tools/tools.cpp index 91afd7ad..894b7d9b 100644 --- a/target-ethos/tools/tools.cpp +++ b/target-higan/tools/tools.cpp @@ -1,4 +1,4 @@ -#include "../ethos.hpp" +#include "../higan.hpp" #include "cheat-database.cpp" #include "cheat-editor.cpp" #include "state-manager.cpp" diff --git a/target-ethos/tools/tools.hpp b/target-higan/tools/tools.hpp similarity index 100% rename from target-ethos/tools/tools.hpp rename to target-higan/tools/tools.hpp diff --git a/target-ethos/utility/utility.cpp b/target-higan/utility/utility.cpp similarity index 99% rename from target-ethos/utility/utility.cpp rename to target-higan/utility/utility.cpp index a96a4245..460cf81e 100644 --- a/target-ethos/utility/utility.cpp +++ b/target-higan/utility/utility.cpp @@ -1,4 +1,4 @@ -#include "../ethos.hpp" +#include "../higan.hpp" Utility* utility = nullptr; diff --git a/target-ethos/utility/utility.hpp b/target-higan/utility/utility.hpp similarity index 100% rename from target-ethos/utility/utility.hpp rename to target-higan/utility/utility.hpp diff --git a/target-ethos/window/window.cpp b/target-higan/window/window.cpp similarity index 97% rename from target-ethos/window/window.cpp rename to target-higan/window/window.cpp index 94753849..582f3817 100644 --- a/target-ethos/window/window.cpp +++ b/target-higan/window/window.cpp @@ -1,4 +1,4 @@ -#include "../ethos.hpp" +#include "../higan.hpp" WindowManager* windowManager = nullptr; void WindowManager::append(Window* window, string name) { diff --git a/target-ethos/window/window.hpp b/target-higan/window/window.hpp similarity index 100% rename from target-ethos/window/window.hpp rename to target-higan/window/window.hpp diff --git a/target-loki/Makefile b/target-loki/Makefile index ba72d210..ce4fa934 100644 --- a/target-loki/Makefile +++ b/target-loki/Makefile @@ -6,7 +6,9 @@ include processor/Makefile include sfc/Makefile include gb/Makefile -ui_objects := ui-loki ui-interface ui-presentation ui-terminal +ui_objects := ui-loki ui-settings +ui_objects += ui-interface ui-debugger +ui_objects += ui-presentation ui-terminal ui_objects += ruby phoenix ui_objects += $(if $(call streq,$(platform),windows),resource) @@ -30,7 +32,9 @@ objects := $(ui_objects) $(objects) objects := $(patsubst %,obj/%.o,$(objects)) obj/ui-loki.o: $(ui)/loki.cpp $(call rwildcard,$(ui)/) +obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/) obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/) +obj/ui-debugger.o: $(ui)/debugger/debugger.cpp $(call rwildcard,$(ui)/) obj/ui-presentation.o: $(ui)/presentation/presentation.cpp $(call rwildcard,$(ui)/) obj/ui-terminal.o: $(ui)/terminal/terminal.cpp $(call rwildcard,$(ui)/) diff --git a/target-loki/debugger/debugger.cpp b/target-loki/debugger/debugger.cpp new file mode 100644 index 00000000..74ce21b2 --- /dev/null +++ b/target-loki/debugger/debugger.cpp @@ -0,0 +1,222 @@ +#include "../loki.hpp" +Debugger* debugger = nullptr; + +Debugger::Debugger() { + debugger = this; + SFC::cpu.debugger.op_exec = {&Debugger::cpuExec, this}; + SFC::cpu.debugger.op_read = {&Debugger::cpuRead, this}; + SFC::cpu.debugger.op_write = {&Debugger::cpuWrite, this}; +} + +void Debugger::load() { + usageCPU = new uint8_t[0x1000000](); + file fp; + if(fp.open({interface->pathname, "loki/usage.cpu.bin"}, file::mode::read)) { + if(fp.size() == 0x1000000) { + fp.read(usageCPU, 0x1000000); + } + fp.close(); + } +} + +void Debugger::unload() { + if(tracerFile.open()) tracerFile.close(); + + file fp; + if(fp.open({interface->pathname, "loki/usage.cpu.bin"}, file::mode::write)) { + fp.write(usageCPU, 0x1000000); + fp.close(); + } + delete[] usageCPU; + usageCPU = nullptr; +} + +void Debugger::run() { + switch(mode) { + case Mode::Break: + usleep(20 * 1000); + break; + + case Mode::Run: + emulator->run(); + break; + + case Mode::Step: + emulator->run(); + break; + } +} + +void Debugger::stop() { + mode = Mode::Break; + runFor = false; + runTo = false; +} + +string Debugger::cpuDisassemble() { + char text[4096]; + SFC::cpu.disassemble_opcode(text); + return text; +} + +string Debugger::cpuDisassemble(unsigned addr, bool e, bool m, bool x) { + char text[4096]; + SFC::cpu.disassemble_opcode(text, addr, e, m, x); + return text; +} + +void Debugger::cpuExec(uint24 addr) { + usageCPU[addr] |= Usage::Execute; + if(SFC::cpu.regs.e == 0) usageCPU[addr] &= ~Usage::FlagE; + if(SFC::cpu.regs.p.m == 0) usageCPU[addr] &= ~Usage::FlagM; + if(SFC::cpu.regs.p.x == 0) usageCPU[addr] &= ~Usage::FlagX; + if(SFC::cpu.regs.e == 1) usageCPU[addr] |= Usage::FlagE; + if(SFC::cpu.regs.p.m == 1) usageCPU[addr] |= Usage::FlagM; + if(SFC::cpu.regs.p.x == 1) usageCPU[addr] |= Usage::FlagX; + + if(tracerFile.open()) { + tracerFile.print(cpuDisassemble(), "\n"); + } + + for(unsigned n = 0; n < breakpoints.size(); n++) { + auto& bp = breakpoints[n]; + if(bp.mode != Breakpoint::Mode::Execute) continue; + if(bp.addr != addr) continue; + echo("Breakpoint #", n, " triggered (", ++bp.triggered, " time(s))\n"); + echo(cpuDisassemble(), "\n"); + stop(); + SFC::scheduler.debug(); + } + + if(mode == Mode::Run) { + if(runFor) { + if(--runFor() == 0) { + echo(cpuDisassemble(), "\n"); + stop(); + SFC::scheduler.debug(); + return; + } + } + + if(runTo) { + if(addr == runTo()) { + echo(cpuDisassemble(), "\n"); + stop(); + SFC::scheduler.debug(); + return; + } + } + + return; + } + + if(mode == Mode::Step) { + echo(cpuDisassemble(), "\n"); + if(--stepDuration == 0) { + stop(); + SFC::scheduler.debug(); + } + return; + } +} + +void Debugger::cpuRead(uint24 addr, uint8 data) { + usageCPU[addr] |= Usage::Read; + + for(unsigned n = 0; n < breakpoints.size(); n++) { + auto& bp = breakpoints[n]; + if(bp.mode != Breakpoint::Mode::Read) continue; + if(bp.addr != addr) continue; + if(bp.data && bp.data() != data) continue; + echo("Breakpoint #", n, " triggered (", ++bp.triggered, " time(s))\n"); + echo("Read ", hex<2>(data), "\n"); + stop(); + SFC::scheduler.debug(); + } +} + +void Debugger::cpuWrite(uint24 addr, uint8 data) { + usageCPU[addr] |= Usage::Write; + + for(unsigned n = 0; n < breakpoints.size(); n++) { + auto& bp = breakpoints[n]; + if(bp.mode != Breakpoint::Mode::Write) continue; + if(bp.addr != addr) continue; + if(bp.data && bp.data() != data) continue; + echo("Breakpoint #", n, " triggered (", ++bp.triggered, " time(s))\n"); + echo("Wrote ", hex<2>(data), "\n"); + stop(); + SFC::scheduler.debug(); + } +} + +void Debugger::echoBreakpoints() { + if(breakpoints.size() == 0) return; + echo("# type addr data triggered\n"); + echo("--- -------- ------ ---- ---------\n"); + for(unsigned n = 0; n < breakpoints.size(); n++) { + auto& bp = breakpoints[n]; + string output = {format<-3>(n), " "}; + if(bp.mode == Breakpoint::Mode::Disabled) output.append("disabled "); + if(bp.mode == Breakpoint::Mode::Read ) output.append("read "); + if(bp.mode == Breakpoint::Mode::Write ) output.append("write "); + if(bp.mode == Breakpoint::Mode::Execute ) output.append("execute "); + output.append(hex<6>(bp.addr), " "); + output.append(bp.data ? hex<2>(bp.data()) : " ", " "); + output.append(format<-9>(bp.triggered)); + echo(output, "\n"); + } +} + +void Debugger::echoDisassemble(unsigned addr, signed size) { + if(!(usageCPU[addr] & Usage::Execute)) { + echo("No usage data available for this address\n"); + return; + } + + while(size > 0) { + string text = cpuDisassemble(addr, usageCPU[addr] & Usage::FlagE, usageCPU[addr] & Usage::FlagM, usageCPU[addr] & Usage::FlagX); + echo(text, "\n"); + if(--size <= 0) break; + + unsigned displacement = 1; + while(displacement < 5) { //maximum opcode length is four bytes + if(usageCPU[addr + displacement] & Usage::Execute) break; + displacement++; + } + if(displacement >= 5) { + echo("...\n"); + return; + } + addr += displacement; + } +} + +void Debugger::echoHex(unsigned addr, signed size) { + while(size > 0) { + string hexdata, asciidata; + for(unsigned n = 0; n < 16; n++) { + unsigned offset = addr; + if((offset & 0x40e000) == 0x002000 || (offset & 0x40e000) == 0x004000) { + //$00-3f,80-bf:2000-5fff + //reading MMIO registers can negatively impact emulation, so disallow these reads + hexdata.append("?? "); + asciidata.append("?"); + } else { + uint8_t byte = SFC::bus.read(addr + n); + hexdata.append(hex<2>(byte), " "); + asciidata.append(byte >= 0x20 && byte <= 0x7e ? (char)byte : '.'); + } + } + echo(hex<6>(addr), " [ ", hexdata, "] ", asciidata, "\n"); + addr += 16, size -= 16; + } +} + +uint8_t Debugger::read(unsigned addr) { + return SFC::bus.read(addr); +} + +void Debugger::write(unsigned addr, uint8_t data) { + return SFC::bus.write(addr, data); +} diff --git a/target-loki/debugger/debugger.hpp b/target-loki/debugger/debugger.hpp new file mode 100644 index 00000000..042ad0f3 --- /dev/null +++ b/target-loki/debugger/debugger.hpp @@ -0,0 +1,50 @@ +struct Debugger { + Debugger(); + + void load(); + void unload(); + + void run(); + void stop(); + + string cpuDisassemble(); + string cpuDisassemble(unsigned addr, bool e, bool m, bool x); + void cpuExec(uint24 addr); + void cpuRead(uint24 addr, uint8 data); + void cpuWrite(uint24 addr, uint8 data); + void echoBreakpoints(); + void echoDisassemble(unsigned addr, signed size); + void echoHex(unsigned addr, signed size); + uint8_t read(unsigned addr); + void write(unsigned addr, uint8_t data); + + enum class Mode : unsigned { Break, Run, Step } mode = Mode::Break; + + struct Breakpoint { + enum class Mode : unsigned { Disabled, Read, Write, Execute } mode = Mode::Disabled; + unsigned addr = 0; + optional data = false; + unsigned triggered = 0; //counter for number of times breakpoint was hit + }; + + struct Usage { + enum : unsigned { + Read = 0x01, + Write = 0x02, + Execute = 0x04, + FlagE = 0x08, + FlagM = 0x10, + FlagX = 0x20, + }; + }; + + vector breakpoints; + optional runFor = false; + optional runTo = false; + unsigned stepDuration = 0; + file tracerFile; + bool tracerMask = false; + uint8_t* usageCPU = nullptr; +}; + +extern Debugger* debugger; diff --git a/target-loki/interface/interface.cpp b/target-loki/interface/interface.cpp index 830ccadf..094ad718 100644 --- a/target-loki/interface/interface.cpp +++ b/target-loki/interface/interface.cpp @@ -13,19 +13,21 @@ bool Interface::load(string pathname) { if(!directory::exists(pathname)) return false; string type = extension(pathname); - pathname.append("/"); for(auto& media : emulator->media) { if(media.bootable == false) continue; if(type != media.type) continue; + this->pathname = pathname.append("/"); pathnames.reset(); pathnames(0) = program->path({media.name, ".sys/"}); pathnames(media.id) = pathname; + echo("Loaded ", pathname, "\n"); emulator->load(media.id); emulator->paletteUpdate(Emulator::Interface::PaletteMode::Standard); emulator->power(); + presentation->setTitle(emulator->title()); return true; } @@ -66,12 +68,14 @@ void Interface::loadRequest(unsigned id, string path) { if(file::exists(pathname) == false) return; mmapstream stream(pathname); emulator->load(id, stream); + echo("Loaded ", path, "\n"); } void Interface::saveRequest(unsigned id, string path) { string pathname = {pathnames(emulator->group(id)), path}; filestream stream(pathname, file::mode::write); emulator->save(id, stream); + echo("Saved ", path, "\n"); } uint32_t Interface::videoColor(unsigned source, uint16_t alpha, uint16_t red, uint16_t green, uint16_t blue) { @@ -101,6 +105,7 @@ void Interface::videoRefresh(const uint32_t* palette, const uint32_t* data, unsi } void Interface::audioSample(int16_t lsample, int16_t rsample) { + if(settings->audio.mute) lsample = 0, rsample = 0; signed samples[] = {lsample, rsample}; dspaudio.sample(samples); while(dspaudio.pending()) { diff --git a/target-loki/interface/interface.hpp b/target-loki/interface/interface.hpp index d4089646..162f02f3 100644 --- a/target-loki/interface/interface.hpp +++ b/target-loki/interface/interface.hpp @@ -18,6 +18,7 @@ struct Interface : Emulator::Interface::Bind { string server(); void notify(string text); + string pathname; //path to game folder lstring pathnames; struct Gamepad { bool up = false; diff --git a/target-loki/loki.cpp b/target-loki/loki.cpp index f4d36d0d..b9e71bdb 100644 --- a/target-loki/loki.cpp +++ b/target-loki/loki.cpp @@ -15,12 +15,7 @@ string Program::path(string name) { } void Program::main() { - if(pause) { - usleep(20 * 1000); - return; - } - - emulator->run(); + debugger->run(); } Program::Program(string pathname) { @@ -31,7 +26,9 @@ Program::Program(string pathname) { sharedpath = {nall::sharedpath(), "loki/"}; directory::create(userpath); + new Settings; new Interface; + new Debugger; new Presentation; new Terminal; @@ -39,19 +36,19 @@ Program::Program(string pathname) { terminal->setVisible(); Application::processEvents(); - video.driver(video.optimalDriver()); + video.driver(settings->video.driver); video.set(Video::Handle, presentation->viewport.handle()); - video.set(Video::Synchronize, false); + video.set(Video::Synchronize, settings->video.synchronize); video.set(Video::Filter, Video::FilterNearest); if(video.init() == false) { video.driver("None"); video.init(); } - audio.driver(audio.optimalDriver()); + audio.driver(settings->audio.driver); audio.set(Audio::Handle, presentation->viewport.handle()); - audio.set(Audio::Synchronize, true); + audio.set(Audio::Synchronize, settings->audio.synchronize); audio.set(Audio::Frequency, 48000u); if(audio.init() == false) { audio.driver("None"); audio.init(); } - input.driver(input.optimalDriver()); + input.driver(settings->input.driver); input.set(Input::Handle, presentation->viewport.handle()); if(input.init() == false) { input.driver("None"); input.init(); } input.onChange = {&Interface::inputEvent, interface}; @@ -65,11 +62,14 @@ Program::Program(string pathname) { presentation->showSplash(); interface->load(pathname); + debugger->load(); Application::main = {&Program::main, this}; Application::run(); + debugger->unload(); interface->unload(); + settings->save(); } int main(int argc, char** argv) { diff --git a/target-loki/loki.hpp b/target-loki/loki.hpp index 0bf2d332..c4b93d5b 100644 --- a/target-loki/loki.hpp +++ b/target-loki/loki.hpp @@ -1,5 +1,6 @@ #include -#include +#include +namespace SFC = SuperFamicom; #include #include @@ -19,7 +20,9 @@ using namespace ruby; #include using namespace phoenix; +#include "settings/settings.hpp" #include "interface/interface.hpp" +#include "debugger/debugger.hpp" #include "presentation/presentation.hpp" #include "terminal/terminal.hpp" #include "resource/resource.hpp" @@ -29,12 +32,14 @@ struct Program { string userpath; string sharedpath; - bool pause = true; - string path(string name); void main(); Program(string pathname); }; +template void echo(Args&&... args) { + terminal->print({std::forward(args)...}); +} + extern Program* program; extern DSP dspaudio; diff --git a/target-loki/presentation/presentation.cpp b/target-loki/presentation/presentation.cpp index 2e609b0c..147e83af 100644 --- a/target-loki/presentation/presentation.cpp +++ b/target-loki/presentation/presentation.cpp @@ -14,7 +14,7 @@ Presentation::Presentation() { onClose = &Application::quit; splash.allocate(512, 480); - splash.verticalGradient(0xff00003f, 0xff000000, 512, 480, 256, 0); + splash.verticalGradient(0xff00005f, 0xff000000, 512, 480, 256, 0); nall::image floor; floor.allocate(512, 480); floor.radialGradient(0xffff0000, 0x00000000, 384, 240, 256, 415); diff --git a/target-loki/settings/settings.cpp b/target-loki/settings/settings.cpp new file mode 100644 index 00000000..1ccb2061 --- /dev/null +++ b/target-loki/settings/settings.cpp @@ -0,0 +1,43 @@ +#include "../loki.hpp" +Settings* settings = nullptr; + +Settings::Settings() { + settings = this; + + video.append(video.driver = ruby::video.optimalDriver(), "Driver"); + video.append(video.synchronize = false, "Synchronize"); + append(video, "Video"); + + audio.append(audio.driver = ruby::audio.optimalDriver(), "Driver"); + audio.append(audio.synchronize = true, "Synchronize"); + audio.append(audio.mute = false, "Mute"); + append(audio, "Audio"); + + input.append(input.driver = ruby::input.optimalDriver(), "Driver"); + append(input, "Input"); + + load(); +} + +void Settings::load() { + Configuration::Document::load(program->path("settings.bml")); + save(); //create configuration file if it does not exist +} + +void Settings::save() { + Configuration::Document::save(program->path("settings.bml")); +} + +void Settings::command(string s, lstring args) { + unsigned argc = args.size(); + s.ltrim<1>("settings."); + + if(s == "video.driver" && argc == 1) { video.driver = args[0]; return; } + if(s == "video.synchronize" && argc == 1) { video.synchronize = args[0] != "false"; ruby::video.set(ruby::Video::Synchronize, video.synchronize); return; } + if(s == "audio.driver" && argc == 1) { audio.driver = args[0]; return; } + if(s == "audio.synchronize" && argc == 1) { audio.synchronize = args[0] != "false"; ruby::audio.set(ruby::Audio::Synchronize, audio.synchronize); return; } + if(s == "audio.mute" && argc == 1) { audio.mute = args[0] != "false"; return; } + if(s == "input.driver" && argc == 1) { input.driver = args[0]; return; } + + echo("Error: unrecognized setting: ", s, "\n"); +} diff --git a/target-loki/settings/settings.hpp b/target-loki/settings/settings.hpp new file mode 100644 index 00000000..fccf39a8 --- /dev/null +++ b/target-loki/settings/settings.hpp @@ -0,0 +1,23 @@ +struct Settings : Configuration::Document { + struct Video : Configuration::Node { + string driver; + bool synchronize; + } video; + + struct Audio : Configuration::Node { + string driver; + bool synchronize; + bool mute; + } audio; + + struct Input : Configuration::Node { + string driver; + } input; + + Settings(); + void load(); + void save(); + void command(string s, lstring args); +}; + +extern Settings* settings; diff --git a/target-loki/terminal/terminal.cpp b/target-loki/terminal/terminal.cpp index 4bf1a661..e9dddbfc 100644 --- a/target-loki/terminal/terminal.cpp +++ b/target-loki/terminal/terminal.cpp @@ -4,11 +4,11 @@ Terminal* terminal = nullptr; Terminal::Terminal() { terminal = this; + setTitle({"loki v", Emulator::Version}); setWindowGeometry({0, 480 + frameMargin().height, 800, 480}); console.setFont(Font::monospace(8)); - print("loki v", Emulator::Version, "\n\n"); - print("$ "); + console.setPrompt("$ "); layout.append(console, {~0, ~0}); append(layout); @@ -17,26 +17,151 @@ Terminal::Terminal() { console.onActivate = {&Terminal::command, this}; } -void Terminal::command(string s) { - if(s.empty()) { - } else if(s == "quit" || s == "exit") { - Application::quit(); - } else if(s == "clear" || s == "reset") { - reset(); - } else if(s == "r") { - program->pause = false; - } else if(s == "p") { - program->pause = true; - } else { - print("unrecognized command\n"); +void Terminal::command(string t) { + lstring args = t.qsplit(" "); + string s = args.takeFirst(); + unsigned argc = args.size(); + + if(s.empty()) return; + + if(s.beginsWith("settings.")) return settings->command(s, args); + + if(s == "break") { + debugger->stop(); + return; } - print("$ "); + + if(s == "breakpoints") { + debugger->echoBreakpoints(); + return; + } + + if(s == "breakpoints.append" && argc >= 2 && argc <= 3) { + Debugger::Breakpoint bp; + if(args[0] == "read" ) bp.mode = Debugger::Breakpoint::Mode::Read; + if(args[0] == "write" ) bp.mode = Debugger::Breakpoint::Mode::Write; + if(args[0] == "execute") bp.mode = Debugger::Breakpoint::Mode::Execute; + bp.addr = hex(args[1]); + if(argc >= 3) bp.data = {true, (uint8_t)hex(args[2])}; + debugger->breakpoints.append(bp); + debugger->echoBreakpoints(); + return; + } + + if(s == "breakpoints.remove" && argc == 1) { + unsigned n = decimal(args[0]); + if(n < debugger->breakpoints.size()) { + debugger->breakpoints.remove(n); + } + debugger->echoBreakpoints(); + return; + } + + if(s == "breakpoints.reset") { + debugger->breakpoints.reset(); + return; + } + + if(s == "clear") { + reset(); + return; + } + + if(s == "disassemble" && argc >= 1 && argc <= 2) { + debugger->echoDisassemble(hex(args[0]), argc == 2 ? decimal(args[1]) : 16); + return; + } + + if(s == "hex" && argc >= 1 && argc <= 2) { + debugger->echoHex(hex(args[0]), argc == 2 ? decimal(args[1]) : 256); + return; + } + + if(s == "quit") { + Application::quit(); + return; + } + + if(s == "read" && argc == 1) { + unsigned addr = hex(args[0]); + uint8_t data = debugger->read(addr); + echo(hex<6>(addr), " = ", hex<2>(data), "\n"); + return; + } + + if(s == "run") { + debugger->mode = Debugger::Mode::Run; + return; + } + + if(s == "run.for" && argc == 1) { + debugger->mode = Debugger::Mode::Run; + debugger->runFor = {true, (unsigned)decimal(args[0])}; + return; + } + + if(s == "run.to" && argc == 1) { + debugger->mode == Debugger::Mode::Run; + debugger->runTo = {true, (unsigned)hex(args[0])}; + return; + } + + if(s == "step" && argc <= 1) { + if(debugger->mode != Debugger::Mode::Break) { + echo("Error: must break before stepping\n"); + return; + } + debugger->mode = Debugger::Mode::Step; + debugger->stepDuration = (argc == 1 ? decimal(args[0]) : 1); + return; + } + + if(s == "tracer.enable" && argc <= 1) { + if(debugger->tracerFile.open() == false) { + string filename = {"trace-", string::datetime().transform(" :", "--"), ".log"}; + if(argc >= 1) filename = args[0]; + string pathname = {interface->pathname, "loki/"}; + directory::create(pathname); + pathname.append(filename); + if(debugger->tracerFile.open(pathname, file::mode::write)) { + echo("Tracer enabled\n"); + } + } + return; + } + + if(s == "tracer.disable") { + if(debugger->tracerFile.open() == true) { + debugger->tracerFile.close(); + echo("Tracer disabled\n"); + } + return; + } + + if(s == "tracer.mask" && argc == 1) { + debugger->tracerMask = args[0] != "false"; + return; + } + + if(s == "usage.reset") { + memset(debugger->usageCPU, 0, 0x1000000); + return; + } + + if(s == "write" && argc == 2) { + unsigned addr = hex(args[0]); + uint8_t data = hex(args[1]); + debugger->write(addr, data); + return; + } + + echo("Error: unrecognized command: ", s, "\n"); } void Terminal::reset() { console.reset(); } -template void Terminal::print(Args&&... args) { - console.print(std::forward(args)...); +void Terminal::print(const string& text) { + console.print(text); } diff --git a/target-loki/terminal/terminal.hpp b/target-loki/terminal/terminal.hpp index 39e54c1b..2ffd0120 100644 --- a/target-loki/terminal/terminal.hpp +++ b/target-loki/terminal/terminal.hpp @@ -5,7 +5,7 @@ struct Terminal : Window { Terminal(); void command(string s); void reset(); - template void print(Args&&... args); + void print(const string& text); }; extern Terminal* terminal;