From 3016e595f0a0bdd088cd5f95b082cb73c78e7c3c Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 9 Feb 2014 16:59:46 +1100 Subject: [PATCH] Update to v094r06 release. byuu says: New terminal is in. Much nicer to use now. Command history makes a major difference in usability. The SMP is now fully traceable and debuggable. Basically they act as separate entities, you can trace both at the same time, but for the most part running and stepping is performed on the chip you select. I'm going to put off CPU+SMP interleave support for a while. I don't actually think it'll be too hard. Will get trickier if/when we support coprocessor debugging. Remaining tasks: - aliases - hotkeys - save states - window geometry Basically, the debugger's done. Just have to add the UI fluff. I also removed tracing/memory export from higan. It was always meant to be temporary until the debugger was remade. --- Makefile | 4 +- emulator/emulator.hpp | 2 +- emulator/interface.hpp | 4 - fc/cheat/cheat.cpp | 6 +- fc/cheat/cheat.hpp | 2 +- gb/cheat/cheat.cpp | 6 +- gb/cheat/cheat.hpp | 2 +- gba/player/player.cpp | 23 ++- gba/player/player.hpp | 4 +- nall/hashset.hpp | 12 +- nall/hid.hpp | 12 +- nall/ips.hpp | 100 ------------- nall/map.hpp | 10 +- nall/maybe.hpp | 76 ++++++++++ nall/nall.hpp | 1 + nall/set.hpp | 14 +- nall/string/base.hpp | 10 +- nall/string/char/base.hpp | 10 +- nall/string/char/strpos.hpp | 16 +-- nall/string/eval/evaluator.hpp | 12 +- nall/string/list.hpp | 6 +- nall/string/wrapper.hpp | 8 +- nall/ups.hpp | 225 ------------------------------ nall/utility.hpp | 116 --------------- nall/vector.hpp | 7 +- phoenix/gtk/font.cpp | 4 +- phoenix/gtk/platform.hpp | 6 +- phoenix/gtk/widget/console.cpp | 148 ++++++++++++++------ phoenix/qt/font.cpp | 4 +- phoenix/qt/platform.moc | 2 +- phoenix/windows/font.cpp | 4 +- processor/spc700/disassembler.cpp | 4 +- processor/spc700/spc700.hpp | 2 +- sfc/cheat/cheat.cpp | 6 +- sfc/cheat/cheat.hpp | 2 +- sfc/cpu/cpu.cpp | 6 - sfc/interface/interface.cpp | 33 ----- sfc/interface/interface.hpp | 5 - target-higan/input/hotkeys.cpp | 22 --- target-higan/utility/utility.cpp | 16 --- target-higan/utility/utility.hpp | 7 +- target-loki/debugger/debugger.cpp | 208 +++++++++++++++++++-------- target-loki/debugger/debugger.hpp | 41 ++++-- target-loki/terminal/terminal.cpp | 70 ++++++---- 44 files changed, 504 insertions(+), 774 deletions(-) delete mode 100644 nall/ips.hpp create mode 100644 nall/maybe.hpp delete mode 100644 nall/ups.hpp diff --git a/Makefile b/Makefile index c5241339..817f860f 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,8 @@ gb := gb gba := gba profile := accuracy -target := higan -# target := loki +# target := higan +target := loki ifeq ($(target),loki) options += debugger diff --git a/emulator/emulator.hpp b/emulator/emulator.hpp index cf2c9785..7ce051a2 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.05"; + static const char Version[] = "094.06"; static const char Author[] = "byuu"; static const char License[] = "GPLv3"; static const char Website[] = "http://byuu.org/"; diff --git a/emulator/interface.hpp b/emulator/interface.hpp index 26ad8906..b46fdfe4 100644 --- a/emulator/interface.hpp +++ b/emulator/interface.hpp @@ -111,10 +111,6 @@ struct Interface { //utility functions enum class PaletteMode : unsigned { Literal, Channel, Standard, Emulation }; virtual void paletteUpdate(PaletteMode mode) {} - - //debugger functions - virtual bool tracerEnable(bool) { return false; } - virtual void exportMemory() {} }; } diff --git a/fc/cheat/cheat.cpp b/fc/cheat/cheat.cpp index 73854559..3d1e1f57 100644 --- a/fc/cheat/cheat.cpp +++ b/fc/cheat/cheat.cpp @@ -16,13 +16,13 @@ void Cheat::append(unsigned addr, unsigned comp, unsigned data) { codes.append({addr, comp, data}); } -optional Cheat::find(unsigned addr, unsigned comp) { +maybe Cheat::find(unsigned addr, unsigned comp) { for(auto& code : codes) { if(code.addr == addr && (code.comp == Unused || code.comp == comp)) { - return {true, code.data}; + return code.data; } } - return false; + return nothing; } } diff --git a/fc/cheat/cheat.hpp b/fc/cheat/cheat.hpp index c1cb490a..43f2d05c 100644 --- a/fc/cheat/cheat.hpp +++ b/fc/cheat/cheat.hpp @@ -11,7 +11,7 @@ struct Cheat { void reset(); void append(unsigned addr, unsigned data); void append(unsigned addr, unsigned comp, unsigned data); - optional find(unsigned addr, unsigned comp); + maybe find(unsigned addr, unsigned comp); }; extern Cheat cheat; diff --git a/gb/cheat/cheat.cpp b/gb/cheat/cheat.cpp index 3457d565..7b45725b 100644 --- a/gb/cheat/cheat.cpp +++ b/gb/cheat/cheat.cpp @@ -16,13 +16,13 @@ void Cheat::append(unsigned addr, unsigned comp, unsigned data) { codes.append({addr, comp, data}); } -optional Cheat::find(unsigned addr, unsigned comp) { +maybe Cheat::find(unsigned addr, unsigned comp) { for(auto& code : codes) { if(code.addr == addr && (code.comp == Unused || code.comp == comp)) { - return {true, code.data}; + return code.data; } } - return false; + return nothing; } } diff --git a/gb/cheat/cheat.hpp b/gb/cheat/cheat.hpp index c1cb490a..43f2d05c 100644 --- a/gb/cheat/cheat.hpp +++ b/gb/cheat/cheat.hpp @@ -11,7 +11,7 @@ struct Cheat { void reset(); void append(unsigned addr, unsigned data); void append(unsigned addr, unsigned comp, unsigned data); - optional find(unsigned addr, unsigned comp); + maybe find(unsigned addr, unsigned comp); }; extern Cheat cheat; diff --git a/gba/player/player.cpp b/gba/player/player.cpp index a1229532..4248b916 100644 --- a/gba/player/player.cpp +++ b/gba/player/player.cpp @@ -56,21 +56,20 @@ void Player::frame() { } } -optional Player::keyinput() { - if(status.logoDetected == false) return false; - - switch(status.logoCounter) { - case 0: return {true, 0x03ff}; - case 1: return {true, 0x03ff}; - case 2: return {true, 0x030f}; +maybe Player::keyinput() { + if(status.logoDetected) { + switch(status.logoCounter) { + case 0: return 0x03ff; + case 1: return 0x03ff; + case 2: return 0x030f; + } } - unreachable; + return nothing; } -optional Player::read() { - if(status.enable == false) return false; - - return {true, status.send}; +maybe Player::read() { + if(status.enable) return status.send; + return nothing; } void Player::write(uint8 byte, uint2 addr) { diff --git a/gba/player/player.hpp b/gba/player/player.hpp index c9280620..8b73da1a 100644 --- a/gba/player/player.hpp +++ b/gba/player/player.hpp @@ -14,8 +14,8 @@ struct Player { void power(); void frame(); - optional keyinput(); - optional read(); + maybe keyinput(); + maybe read(); void write(uint8 byte, uint2 addr); void serialize(serializer& s); diff --git a/nall/hashset.hpp b/nall/hashset.hpp index 3f51199c..58bc136f 100644 --- a/nall/hashset.hpp +++ b/nall/hashset.hpp @@ -88,19 +88,19 @@ public: length = size; } - optional find(const T& value) { - if(!pool) return false; + maybe find(const T& value) { + if(!pool) return nothing; unsigned hash = value.hash() & (length - 1); while(pool[hash]) { - if(value == *pool[hash]) return {true, *pool[hash]}; + if(value == *pool[hash]) return *pool[hash]; if(++hash >= length) hash = 0; } - return false; + return nothing; } - optional insert(const T& value) { + maybe insert(const T& value) { if(!pool) pool = new T*[length](); //double pool size when load is >= 50% @@ -111,7 +111,7 @@ public: while(pool[hash]) if(++hash >= length) hash = 0; pool[hash] = new T(value); - return {true, *pool[hash]}; + return *pool[hash]; } bool remove(const T& value) { diff --git a/nall/hid.hpp b/nall/hid.hpp index dc708886..77e67060 100644 --- a/nall/hid.hpp +++ b/nall/hid.hpp @@ -23,11 +23,11 @@ namespace HID { input.append({name}); } - optional find(const string& name) { + maybe find(const string& name) { for(unsigned id = 0; id < input.size(); id++) { - if(input[id].name == name) return {true, id}; + if(input[id].name == name) return id; } - return false; + return nothing; } }; @@ -50,11 +50,11 @@ namespace HID { group.append({name}); } - optional find(const string& name) { + maybe find(const string& name) { for(unsigned id = 0; id < group.size(); id++) { - if(group[id].name == name) return {true, id}; + if(group[id].name == name) return id; } - return false; + return nothing; } }; diff --git a/nall/ips.hpp b/nall/ips.hpp deleted file mode 100644 index 1159dee1..00000000 --- a/nall/ips.hpp +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef NALL_IPS_HPP -#define NALL_IPS_HPP - -#include -#include -#include - -namespace nall { - -struct ips { - inline bool apply(); - inline void source(const uint8_t* data, unsigned size); - inline void modify(const uint8_t* data, unsigned size); - inline ips(); - inline ~ips(); - - uint8_t* data = nullptr; - unsigned size = 0; - const uint8_t* sourceData = nullptr; - unsigned sourceSize = 0; - const uint8_t* modifyData = nullptr; - unsigned modifySize = 0; -}; - -bool ips::apply() { - if(modifySize < 8) return false; - if(modifyData[0] != 'P') return false; - if(modifyData[1] != 'A') return false; - if(modifyData[2] != 'T') return false; - if(modifyData[3] != 'C') return false; - if(modifyData[4] != 'H') return false; - - if(data) delete[] data; - data = new uint8_t[16 * 1024 * 1024 + 65536](); //maximum size of IPS patch + single-tag padding - size = sourceSize; - memcpy(data, sourceData, sourceSize); - unsigned offset = 5; - - while(true) { - unsigned address, length; - - if(offset > modifySize - 3) break; - address = modifyData[offset++] << 16; - address |= modifyData[offset++] << 8; - address |= modifyData[offset++] << 0; - - if(address == 0x454f46) { //EOF - if(offset == modifySize) return true; - if(offset == modifySize - 3) { - size = modifyData[offset++] << 16; - size |= modifyData[offset++] << 8; - size |= modifyData[offset++] << 0; - return true; - } - } - - if(offset > modifySize - 2) break; - length = modifyData[offset++] << 8; - length |= modifyData[offset++] << 0; - - if(length) { //Copy - if(offset > modifySize - length) break; - while(length--) data[address++] = modifyData[offset++]; - } else { //RLE - if(offset > modifySize - 3) break; - length = modifyData[offset++] << 8; - length |= modifyData[offset++] << 0; - if(length == 0) break; //illegal - while(length--) data[address++] = modifyData[offset]; - offset++; - } - - size = max(size, address); - } - - delete[] data; - data = nullptr; - return false; -} - -void ips::source(const uint8_t* data, unsigned size) { - sourceData = data, sourceSize = size; -} - -void ips::modify(const uint8_t* data, unsigned size) { - modifyData = data, modifySize = size; -} - -ips::ips() { -} - -ips::~ips() { - if(data) delete[] data; - if(sourceData) delete[] sourceData; - if(modifyData) delete[] modifyData; -} - -} - -#endif diff --git a/nall/map.hpp b/nall/map.hpp index 56e4b5c8..72c99ea5 100644 --- a/nall/map.hpp +++ b/nall/map.hpp @@ -16,9 +16,9 @@ template struct map { node_t(const T& key, const U& value) : key(key), value(value) {} }; - optional find(const T& key) const { - if(auto node = root.find({key})) return {true, node().value}; - return false; + maybe find(const T& key) const { + if(auto node = root.find({key})) return node().value; + return nothing; } void insert(const T& key, const U& value) { root.insert({key, value}); } @@ -36,8 +36,8 @@ protected: }; template struct bimap { - optional find(const T& key) const { return tmap.find(key); } - optional find(const U& key) const { return umap.find(key); } + maybe find(const T& key) const { return tmap.find(key); } + maybe find(const U& key) const { return umap.find(key); } void insert(const T& key, const U& value) { tmap.insert(key, value); umap.insert(value, key); } void remove(const T& key) { if(auto p = tmap.find(key)) { umap.remove(p().value); tmap.remove(key); } } void remove(const U& key) { if(auto p = umap.find(key)) { tmap.remove(p().value); umap.remove(key); } } diff --git a/nall/maybe.hpp b/nall/maybe.hpp new file mode 100644 index 00000000..4f806dac --- /dev/null +++ b/nall/maybe.hpp @@ -0,0 +1,76 @@ +#ifndef NALL_MAYBE_HPP +#define NALL_MAYBE_HPP + +namespace nall { + +struct nothing_t {}; +static nothing_t nothing; + +template +class maybe { + T* value = nullptr; + +public: + maybe() {} + maybe(nothing_t) {} + maybe(const T& source) { operator=(source); } + maybe(const maybe& source) { operator=(source); } + maybe(maybe&& source) { operator=(std::move(source)); } + ~maybe() { reset(); } + + maybe& operator=(nothing_t) { reset(); return *this; } + maybe& operator=(const T& source) { reset(); value = new T(source); return *this; } + maybe& operator=(const maybe& source) { reset(); if(source) value = new T(source()); return *this; } + maybe& operator=(maybe&& source) { reset(); value = source.value; source.value = nullptr; return *this; } + + bool operator==(const maybe& source) const { + if(value && source.value) return *value == *source.value; + return !value && !source.value; + } + bool operator!=(const maybe& source) const { return !operator==(source); } + + explicit operator bool() const { return value; } + T& operator()() { assert(value); return *value; } + const T& operator()() const { assert(value); return *value; } + const T& operator()(const T& invalid) const { if(value) return *value; return invalid; } + + bool empty() const { return value == nullptr; } + void reset() { if(value) { delete value; value = nullptr; } } + void swap(maybe& source) { std::swap(value, source.value); } +}; + +template +class maybe { + T* value = nullptr; + +public: + maybe() {} + maybe(nothing_t) {} + maybe(const T& source) { operator=(source); } + maybe(const maybe& source) { operator=(source); } + maybe(maybe&& source) { operator=(std::move(source)); } + + maybe& operator=(nothing_t) { value = nullptr; return *this; } + maybe& operator=(const T& source) { value = (T*)&source; return *this; } + maybe& operator=(const maybe& source) { value = source.value; return *this; } + maybe& operator=(maybe&& source) { value = source.value; source.value = nullptr; return *this; } + + bool operator==(const maybe& source) const { + if(value && source.value) return *value == *source.value; + return !value && !source.value; + } + bool operator!=(const maybe& source) const { return !operator==(source); } + + explicit operator bool() const { return value; } + T& operator()() { assert(value); return *value; } + const T& operator()() const { assert(value); return *value; } + const T& operator()(const T& invalid) const { if(value) return *value; return invalid; } + + bool empty() const { return value == nullptr; } + void reset() { value = nullptr; } + void swap(maybe& source) { std::swap(value, source.value); } +}; + +} + +#endif diff --git a/nall/nall.hpp b/nall/nall.hpp index 871e2d51..0b56d50a 100644 --- a/nall/nall.hpp +++ b/nall/nall.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include diff --git a/nall/set.hpp b/nall/set.hpp index c8003ec0..d463296d 100644 --- a/nall/set.hpp +++ b/nall/set.hpp @@ -45,22 +45,22 @@ template struct set { nodes = 0; } - optional find(const T& value) { + maybe find(const T& value) { if(node_t* node = find(root, value)) return node->value; - return false; + return nothing; } - optional find(const T& value) const { + maybe find(const T& value) const { if(node_t* node = find(root, value)) return node->value; - return false; + return nothing; } - optional insert(const T& value) { + maybe insert(const T& value) { unsigned count = size(); node_t* v = insert(root, value); root->red = 0; - if(size() == count) return false; - return {true, v->value}; + if(size() == count) return nothing; + return v->value; } template bool insert(const T& value, Args&&... args) { diff --git a/nall/string/base.hpp b/nall/string/base.hpp index 7ba6f0fc..8da9d880 100644 --- a/nall/string/base.hpp +++ b/nall/string/base.hpp @@ -107,10 +107,10 @@ public: inline string& strip(); - inline optional find(rstring key) const; - inline optional ifind(rstring key) const; - inline optional qfind(rstring key) const; - inline optional iqfind(rstring key) const; + inline maybe find(rstring key) const; + inline maybe ifind(rstring key) const; + inline maybe qfind(rstring key) const; + inline maybe iqfind(rstring key) const; //core.hpp inline explicit operator bool() const; @@ -155,7 +155,7 @@ public: //list.hpp struct lstring : vector { - inline optional find(rstring) const; + inline maybe find(rstring) const; inline string merge(const string&) const; inline lstring& isort(); inline lstring& strip(); diff --git a/nall/string/char/base.hpp b/nall/string/char/base.hpp index 0a029b2d..49b2fc22 100644 --- a/nall/string/char/base.hpp +++ b/nall/string/char/base.hpp @@ -36,11 +36,11 @@ inline bool strccat(char* target, const char* source, unsigned length); inline void strpcpy(char*& target, const char* source, unsigned& length); //strpos.hpp -inline optional strpos(const char* str, const char* key); -inline optional istrpos(const char* str, const char* key); -inline optional qstrpos(const char* str, const char* key); -inline optional iqstrpos(const char* str, const char* key); -template inline optional ustrpos(const char* str, const char* key); +inline maybe strpos(const char* str, const char* key); +inline maybe istrpos(const char* str, const char* key); +inline maybe qstrpos(const char* str, const char* key); +inline maybe iqstrpos(const char* str, const char* key); +template inline maybe ustrpos(const char* str, const char* key); //trim.hpp template inline char* ltrim(char* str, const char* key = " "); diff --git a/nall/string/char/strpos.hpp b/nall/string/char/strpos.hpp index 19c23217..8c0baa44 100644 --- a/nall/string/char/strpos.hpp +++ b/nall/string/char/strpos.hpp @@ -7,26 +7,26 @@ namespace nall { template -optional ustrpos(const char* str, const char* key) { +maybe ustrpos(const char* str, const char* key) { const char* base = str; while(*str) { if(quoteskip(str)) continue; for(unsigned n = 0;; n++) { - if(key[n] == 0) return {true, (unsigned)(str - base)}; - if(str[n] == 0) return false; + if(key[n] == 0) return (unsigned)(str - base); + if(str[n] == 0) return nothing; if(!chrequal(str[n], key[n])) break; } str++; } - return false; + return nothing; } -optional strpos(const char* str, const char* key) { return ustrpos(str, key); } -optional istrpos(const char* str, const char* key) { return ustrpos(str, key); } -optional qstrpos(const char* str, const char* key) { return ustrpos(str, key); } -optional iqstrpos(const char* str, const char* key) { return ustrpos(str, key); } +maybe strpos(const char* str, const char* key) { return ustrpos(str, key); } +maybe istrpos(const char* str, const char* key) { return ustrpos(str, key); } +maybe qstrpos(const char* str, const char* key) { return ustrpos(str, key); } +maybe iqstrpos(const char* str, const char* key) { return ustrpos(str, key); } } diff --git a/nall/string/eval/evaluator.hpp b/nall/string/eval/evaluator.hpp index 49ac851e..8957a30c 100644 --- a/nall/string/eval/evaluator.hpp +++ b/nall/string/eval/evaluator.hpp @@ -93,16 +93,16 @@ inline int64_t evaluateInteger(Node* node) { throw "invalid operator"; } -inline optional integer(const string& expression) { +inline maybe integer(const string& expression) { try { auto tree = new Node; const char* p = expression; parse(tree, p, 0); auto result = evaluateInteger(tree); delete tree; - return {true, result}; + return result; } catch(const char*) { - return false; + return nothing; } } @@ -138,16 +138,16 @@ inline long double evaluateReal(Node* node) { throw "invalid operator"; } -inline optional real(const string& expression) { +inline maybe real(const string& expression) { try { auto tree = new Node; const char* p = expression; parse(tree, p, 0); auto result = evaluateReal(tree); delete tree; - return {true, result}; + return result; } catch(const char*) { - return false; + return nothing; } } diff --git a/nall/string/list.hpp b/nall/string/list.hpp index 196a7a56..55b2e76e 100644 --- a/nall/string/list.hpp +++ b/nall/string/list.hpp @@ -2,11 +2,11 @@ namespace nall { -optional lstring::find(rstring key) const { +maybe lstring::find(rstring key) const { for(unsigned i = 0; i < size(); i++) { - if(operator[](i) == key) return {true, i}; + if(operator[](i) == key) return i; } - return false; + return nothing; } string lstring::merge(const string& separator) const { diff --git a/nall/string/wrapper.hpp b/nall/string/wrapper.hpp index 0422ecdc..0eadf3dd 100644 --- a/nall/string/wrapper.hpp +++ b/nall/string/wrapper.hpp @@ -114,10 +114,10 @@ string& string::strip() { return *this; } -optional string::find(rstring key) const { return strpos(data(), key); } -optional string::ifind(rstring key) const { return istrpos(data(), key); } -optional string::qfind(rstring key) const { return qstrpos(data(), key); } -optional string::iqfind(rstring key) const { return iqstrpos(data(), key); } +maybe string::find(rstring key) const { return strpos(data(), key); } +maybe string::ifind(rstring key) const { return istrpos(data(), key); } +maybe string::qfind(rstring key) const { return qstrpos(data(), key); } +maybe string::iqfind(rstring key) const { return iqstrpos(data(), key); } } diff --git a/nall/ups.hpp b/nall/ups.hpp deleted file mode 100644 index d26a6519..00000000 --- a/nall/ups.hpp +++ /dev/null @@ -1,225 +0,0 @@ -#ifndef NALL_UPS_HPP -#define NALL_UPS_HPP - -#include -#include -#include -#include - -namespace nall { - -struct ups { - enum class result : unsigned { - unknown, - success, - patch_unwritable, - patch_invalid, - source_invalid, - target_invalid, - target_too_small, - patch_checksum_invalid, - source_checksum_invalid, - target_checksum_invalid, - }; - - function progress; - - result create( - const uint8_t* sourcedata, unsigned sourcelength, - const uint8_t* targetdata, unsigned targetlength, - const char* patchfilename - ) { - source_data = (uint8_t*)sourcedata, target_data = (uint8_t*)targetdata; - source_length = sourcelength, target_length = targetlength; - source_offset = target_offset = 0; - source_checksum = target_checksum = patch_checksum = ~0; - - if(patch_file.open(patchfilename, file::mode::write) == false) return result::patch_unwritable; - - patch_write('U'); - patch_write('P'); - patch_write('S'); - patch_write('1'); - encode(source_length); - encode(target_length); - - unsigned output_length = source_length > target_length ? source_length : target_length; - unsigned relative = 0; - for(unsigned offset = 0; offset < output_length;) { - uint8_t x = source_read(); - uint8_t y = target_read(); - - if(x == y) { - offset++; - continue; - } - - encode(offset++ - relative); - patch_write(x ^ y); - - while(true) { - if(offset >= output_length) { - patch_write(0x00); - break; - } - - x = source_read(); - y = target_read(); - offset++; - patch_write(x ^ y); - if(x == y) break; - } - - relative = offset; - } - - source_checksum = ~source_checksum; - target_checksum = ~target_checksum; - for(unsigned i = 0; i < 4; i++) patch_write(source_checksum >> (i * 8)); - for(unsigned i = 0; i < 4; i++) patch_write(target_checksum >> (i * 8)); - uint32_t patch_result_checksum = ~patch_checksum; - for(unsigned i = 0; i < 4; i++) patch_write(patch_result_checksum >> (i * 8)); - - patch_file.close(); - return result::success; - } - - result apply( - const uint8_t* patchdata, unsigned patchlength, - const uint8_t* sourcedata, unsigned sourcelength, - uint8_t* targetdata, unsigned& targetlength - ) { - patch_data = (uint8_t*)patchdata, source_data = (uint8_t*)sourcedata, target_data = targetdata; - patch_length = patchlength, source_length = sourcelength, target_length = targetlength; - patch_offset = source_offset = target_offset = 0; - patch_checksum = source_checksum = target_checksum = ~0; - - if(patch_length < 18) return result::patch_invalid; - if(patch_read() != 'U') return result::patch_invalid; - if(patch_read() != 'P') return result::patch_invalid; - if(patch_read() != 'S') return result::patch_invalid; - if(patch_read() != '1') return result::patch_invalid; - - unsigned source_read_length = decode(); - unsigned target_read_length = decode(); - - if(source_length != source_read_length && source_length != target_read_length) return result::source_invalid; - targetlength = (source_length == source_read_length ? target_read_length : source_read_length); - if(target_length < targetlength) return result::target_too_small; - target_length = targetlength; - - while(patch_offset < patch_length - 12) { - unsigned length = decode(); - while(length--) target_write(source_read()); - while(true) { - uint8_t patch_xor = patch_read(); - target_write(patch_xor ^ source_read()); - if(patch_xor == 0) break; - } - } - while(source_offset < source_length) target_write(source_read()); - while(target_offset < target_length) target_write(source_read()); - - uint32_t patch_read_checksum = 0, source_read_checksum = 0, target_read_checksum = 0; - for(unsigned i = 0; i < 4; i++) source_read_checksum |= patch_read() << (i * 8); - for(unsigned i = 0; i < 4; i++) target_read_checksum |= patch_read() << (i * 8); - uint32_t patch_result_checksum = ~patch_checksum; - source_checksum = ~source_checksum; - target_checksum = ~target_checksum; - for(unsigned i = 0; i < 4; i++) patch_read_checksum |= patch_read() << (i * 8); - - if(patch_result_checksum != patch_read_checksum) return result::patch_invalid; - if(source_checksum == source_read_checksum && source_length == source_read_length) { - if(target_checksum == target_read_checksum && target_length == target_read_length) return result::success; - return result::target_invalid; - } else if(source_checksum == target_read_checksum && source_length == target_read_length) { - if(target_checksum == source_read_checksum && target_length == source_read_length) return result::success; - return result::target_invalid; - } else { - return result::source_invalid; - } - } - -private: - uint8_t* patch_data = nullptr; - uint8_t* source_data = nullptr; - uint8_t* target_data = nullptr; - unsigned patch_length, source_length, target_length; - unsigned patch_offset, source_offset, target_offset; - unsigned patch_checksum, source_checksum, target_checksum; - file patch_file; - - uint8_t patch_read() { - if(patch_offset < patch_length) { - uint8_t n = patch_data[patch_offset++]; - patch_checksum = crc32_adjust(patch_checksum, n); - return n; - } - return 0x00; - } - - uint8_t source_read() { - if(source_offset < source_length) { - uint8_t n = source_data[source_offset++]; - source_checksum = crc32_adjust(source_checksum, n); - return n; - } - return 0x00; - } - - uint8_t target_read() { - uint8_t result = 0x00; - if(target_offset < target_length) { - result = target_data[target_offset]; - target_checksum = crc32_adjust(target_checksum, result); - } - if(((target_offset++ & 255) == 0) && progress) { - progress(target_offset, source_length > target_length ? source_length : target_length); - } - return result; - } - - void patch_write(uint8_t n) { - patch_file.write(n); - patch_checksum = crc32_adjust(patch_checksum, n); - } - - void target_write(uint8_t n) { - if(target_offset < target_length) { - target_data[target_offset] = n; - target_checksum = crc32_adjust(target_checksum, n); - } - if(((target_offset++ & 255) == 0) && progress) { - progress(target_offset, source_length > target_length ? source_length : target_length); - } - } - - void encode(uint64_t offset) { - while(true) { - uint64_t x = offset & 0x7f; - offset >>= 7; - if(offset == 0) { - patch_write(0x80 | x); - break; - } - patch_write(x); - offset--; - } - } - - uint64_t decode() { - uint64_t offset = 0, shift = 1; - while(true) { - uint8_t x = patch_read(); - offset += (x & 0x7f) * shift; - if(x & 0x80) break; - shift <<= 7; - offset += shift; - } - return offset; - } -}; - -} - -#endif diff --git a/nall/utility.hpp b/nall/utility.hpp index 25609a7c..f574a76b 100644 --- a/nall/utility.hpp +++ b/nall/utility.hpp @@ -1,9 +1,7 @@ #ifndef NALL_UTILITY_HPP #define NALL_UTILITY_HPP -#include #include -#include namespace nall { @@ -12,120 +10,6 @@ template struct base_from_member { base_from_member(T value) : value(value) {} }; -template struct ref { - T& operator*() { - if(type == Type::Reference) return *any_cast(value); - return any_cast(value); - } - - operator T&() { return operator*(); } - - ref(T& value) : type(Type::Reference), value(&value) {} - ref(T&& value) : type(Type::Temporary), value(value) {} - -protected: - enum class Type : unsigned { Reference, Temporary } type; - any value; -}; - -template struct optional { - typedef typename std::remove_reference::type T; - static const bool isConst = std::is_const::value; - static const bool isReference = std::is_reference::value; - struct optional_value_not_valid{}; - - bool valid = false; - T* value = nullptr; - - operator bool() const { return valid; } - - void reset() { - valid = false; - if(value) { - if(!isReference) delete value; - value = nullptr; - } - } - - template::type> - T& operator*() { - if(!valid) throw optional_value_not_valid{}; - return *value; - } - - template::type> - T& operator()() { - if(!valid) throw optional_value_not_valid{}; - return *value; - } - - const T& operator*() const { - if(!valid) throw optional_value_not_valid{}; - return *value; - } - - const T& operator()() const { - if(!valid) throw optional_value_not_valid{}; - return *value; - } - - const T& operator()(const T& alternate) const { - if(!valid) return alternate; - return *value; - } - - const bool operator==(const optional& source) const { - if(valid && source.valid) return *value == *source.value; - if(!valid && !source.valid) return true; - return false; - } - - const bool operator!=(const optional& source) const { - return !operator==(source); - } - - optional& operator=(const T& source) { - reset(); - valid = true; - if(isReference) value = (T*)&source; - else value = new T(source); - return *this; - } - - optional& operator=(T&& source) { - reset(); - valid = true; - if(isReference) value = &source; - else value = new T(std::move(source)); - return *this; - } - - optional& operator=(const optional& source) { - reset(); - if(source) operator=(source()); - return *this; - } - - optional& operator=(optional&& source) { - reset(); - valid = source.valid; - value = source.value; - source.valid = false; - source.value = nullptr; - return *this; - } - - optional() = default; - optional(bool valid) : valid(valid) {} - optional(const T& value) { operator=(value); } - optional(T&& value) { operator=(std::move(value)); } - optional(bool valid, const T& value) : valid(valid) { if(valid) operator=(value); } - optional(bool valid, T&& value) : valid(valid) { if(valid) operator=(std::move(value)); } - optional(const optional& source) { operator=(source); } - optional(optional&& source) { operator=(std::move(source)); } - ~optional() { reset(); } -}; - template inline T* allocate(unsigned size, const T& value) { T* array = new T[size]; for(unsigned i = 0; i < size; i++) array[i] = value; diff --git a/nall/vector.hpp b/nall/vector.hpp index 7ccb53db..d1da089b 100644 --- a/nall/vector.hpp +++ b/nall/vector.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -164,9 +165,9 @@ public: nall::sort(pool + poolbase, objectsize, lessthan); } - optional find(const T& data) { - for(unsigned n = 0; n < objectsize; n++) if(pool[poolbase + n] == data) return {true, n}; - return false; + maybe find(const T& data) { + for(unsigned n = 0; n < objectsize; n++) if(pool[poolbase + n] == data) return n; + return nothing; } T& first() { diff --git a/phoenix/gtk/font.cpp b/phoenix/gtk/font.cpp index 750d47d4..41232cbd 100644 --- a/phoenix/gtk/font.cpp +++ b/phoenix/gtk/font.cpp @@ -36,8 +36,8 @@ PangoFontDescription* pFont::create(string description) { if(part[0] != "") family = part[0]; if(part.size() >= 2) size = decimal(part[1]); - if(part.size() >= 3) bold = part[2].find("Bold"); - if(part.size() >= 3) italic = part[2].find("Italic"); + if(part.size() >= 3) bold = (bool)part[2].find("Bold"); + if(part.size() >= 3) italic = (bool)part[2].find("Italic"); PangoFontDescription* font = pango_font_description_new(); pango_font_description_set_family(font, family); diff --git a/phoenix/gtk/platform.hpp b/phoenix/gtk/platform.hpp index 5c86bc11..e3050f8c 100644 --- a/phoenix/gtk/platform.hpp +++ b/phoenix/gtk/platform.hpp @@ -347,8 +347,9 @@ struct pConsole : public pWidget { Console& console; GtkWidget* subWidget; GtkTextBuffer* textBuffer; - string command; string previousPrompt; + lstring history; + unsigned historyOffset = 0; void print(string text); void reset(); @@ -359,7 +360,8 @@ struct pConsole : public pWidget { void destructor(); void orphan(); bool keyPress(unsigned scancode, unsigned mask); - void seekCursorToEnd(); + void seekToEnd(); + void seekToMark(); }; struct pFrame : public pWidget { diff --git a/phoenix/gtk/widget/console.cpp b/phoenix/gtk/widget/console.cpp index 44d71436..b44db5bf 100644 --- a/phoenix/gtk/widget/console.cpp +++ b/phoenix/gtk/widget/console.cpp @@ -5,34 +5,28 @@ 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 + //insert text before prompt and 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_get_iter_at_line_offset(textBuffer, &iter, gtk_text_buffer_get_line_count(textBuffer), 0); gtk_text_buffer_insert(textBuffer, &iter, text, -1); - seekCursorToEnd(); + seekToEnd(); } void pConsole::reset() { - //flush history and command; draw prompt - command.reset(); + //flush history and redraw prompt gtk_text_buffer_set_text(textBuffer, console.prompt(), -1); - seekCursorToEnd(); + seekToEnd(); } 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()); + //erase previous prompt and replace it with new prompt + GtkTextIter lhs, rhs; + gtk_text_buffer_get_iter_at_line_offset(textBuffer, &lhs, gtk_text_buffer_get_line_count(textBuffer), 0); + gtk_text_buffer_get_iter_at_line_offset(textBuffer, &rhs, gtk_text_buffer_get_line_count(textBuffer), previousPrompt.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; + gtk_text_buffer_get_iter_at_line_offset(textBuffer, &lhs, gtk_text_buffer_get_line_count(textBuffer), 0); + gtk_text_buffer_insert(textBuffer, &lhs, previousPrompt = prompt, -1); + seekToEnd(); } void pConsole::constructor() { @@ -47,7 +41,7 @@ void pConsole::constructor() { textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(subWidget)); - GdkColor background = CreateColor(48, 24, 24); + GdkColor background = CreateColor(72, 24, 24); gtk_widget_modify_base(subWidget, GTK_STATE_NORMAL, &background); GdkColor foreground = CreateColor(255, 255, 255); gtk_widget_modify_text(subWidget, GTK_STATE_NORMAL, &foreground); @@ -70,50 +64,116 @@ void pConsole::orphan() { 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) + GtkTextMark* mark = gtk_text_buffer_get_mark(textBuffer, "insert"); + GtkTextIter start, cursor, end; + gtk_text_buffer_get_iter_at_line_offset(textBuffer, &start, gtk_text_buffer_get_line_count(textBuffer), console.prompt().size()); + gtk_text_buffer_get_iter_at_mark(textBuffer, &cursor, mark); + gtk_text_buffer_get_end_iter(textBuffer, &end); + if(scancode == GDK_KEY_Return || scancode == GDK_KEY_KP_Enter) { - //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(); + char* temp = gtk_text_buffer_get_text(textBuffer, &start, &end, true); + string s = temp; + g_free(temp); + gtk_text_buffer_insert(textBuffer, &end, string{"\n", console.prompt()}, -1); if(console.onActivate) console.onActivate(s); - seekCursorToEnd(); + if(s) history.prepend(s); + if(history.size() > 128) history.removeLast(); + historyOffset = 0; + seekToEnd(); + return true; + } + + if(scancode == GDK_KEY_Up) { + gtk_text_buffer_delete(textBuffer, &start, &end); + gtk_text_buffer_get_end_iter(textBuffer, &end); + if(historyOffset < history.size()) { + gtk_text_buffer_insert(textBuffer, &end, history[historyOffset++], -1); + } + seekToEnd(); + return true; + } + + if(scancode == GDK_KEY_Down) { + gtk_text_buffer_delete(textBuffer, &start, &end); + gtk_text_buffer_get_end_iter(textBuffer, &end); + if(historyOffset > 0) { + gtk_text_buffer_insert(textBuffer, &end, history[--historyOffset], -1); + } + seekToEnd(); + return true; + } + + if(scancode == GDK_KEY_Left) { + if(gtk_text_iter_get_offset(&cursor) <= gtk_text_iter_get_offset(&start)) { + gtk_text_buffer_place_cursor(textBuffer, &start); + } else { + gtk_text_iter_set_offset(&cursor, gtk_text_iter_get_offset(&cursor) - 1); + gtk_text_buffer_place_cursor(textBuffer, &cursor); + } + seekToMark(); + return true; + } + + if(scancode == GDK_KEY_Right) { + if(gtk_text_iter_get_offset(&cursor) < gtk_text_iter_get_offset(&start)) { + gtk_text_buffer_place_cursor(textBuffer, &end); + } else if(gtk_text_iter_get_offset(&cursor) < gtk_text_iter_get_offset(&end)) { + gtk_text_iter_set_offset(&cursor, gtk_text_iter_get_offset(&cursor) + 1); + gtk_text_buffer_place_cursor(textBuffer, &cursor); + } + seekToMark(); + return true; + } + + if(scancode == GDK_KEY_Home) { + gtk_text_buffer_place_cursor(textBuffer, &start); + seekToMark(); + return true; + } + + if(scancode == GDK_KEY_End) { + gtk_text_buffer_place_cursor(textBuffer, &end); + seekToMark(); 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(); + if(gtk_text_iter_get_offset(&cursor) <= gtk_text_iter_get_offset(&start)) return true; + GtkTextIter lhs = cursor; + gtk_text_iter_set_offset(&lhs, gtk_text_iter_get_offset(&cursor) - 1); + gtk_text_buffer_delete(textBuffer, &lhs, &cursor); + seekToMark(); + return true; + } + + if(scancode == GDK_KEY_Delete) { + if(gtk_text_iter_get_offset(&cursor) < gtk_text_iter_get_offset(&start)) return true; + if(gtk_text_iter_get_offset(&cursor) == gtk_text_iter_get_offset(&end)) return true; + GtkTextIter rhs = cursor; + gtk_text_iter_set_offset(&rhs, gtk_text_iter_get_offset(&cursor) + 1); + gtk_text_buffer_delete(textBuffer, &cursor, &rhs); + seekToMark(); return true; } if(scancode >= 0x20 && scancode <= 0x7e) { - //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); + if(gtk_text_iter_get_offset(&cursor) < gtk_text_iter_get_offset(&start)) return true; + gtk_text_buffer_insert(textBuffer, &cursor, string{(char)scancode}, -1); + seekToMark(); return true; } return false; } -void pConsole::seekCursorToEnd() { - //place cursor at end of text buffer; scroll text view to the cursor to ensure it is visible +void pConsole::seekToEnd() { GtkTextIter iter; gtk_text_buffer_get_end_iter(textBuffer, &iter); gtk_text_buffer_place_cursor(textBuffer, &iter); + seekToMark(); +} + +void pConsole::seekToMark() { 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/font.cpp b/phoenix/qt/font.cpp index ce1a6832..3c6fe572 100644 --- a/phoenix/qt/font.cpp +++ b/phoenix/qt/font.cpp @@ -34,8 +34,8 @@ QFont pFont::create(string description) { if(part[0] != "") family = part[0]; if(part.size() >= 2) size = decimal(part[1]); - if(part.size() >= 3) bold = part[2].find("Bold"); - if(part.size() >= 3) italic = part[2].find("Italic"); + if(part.size() >= 3) bold = (bool)part[2].find("Bold"); + if(part.size() >= 3) italic = (bool)part[2].find("Italic"); QFont qtFont; qtFont.setFamily(family); diff --git a/phoenix/qt/platform.moc b/phoenix/qt/platform.moc index 6fd7d8aa..91fc08f6 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: Wed Jan 29 08:08:49 2014 +** Created: Wed Feb 5 08:24:19 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/windows/font.cpp b/phoenix/windows/font.cpp index 19781143..94db0ecf 100644 --- a/phoenix/windows/font.cpp +++ b/phoenix/windows/font.cpp @@ -37,8 +37,8 @@ HFONT pFont::create(string description) { if(part[0] != "") family = part[0]; if(part.size() >= 2) size = decimal(part[1]); - if(part.size() >= 3) bold = part[2].find("Bold"); - if(part.size() >= 3) italic = part[2].find("Italic"); + if(part.size() >= 3) bold = (bool)part[2].find("Bold"); + if(part.size() >= 3) italic = (bool)part[2].find("Italic"); return CreateFont( -(size * 96.0 / 72.0 + 0.5), diff --git a/processor/spc700/disassembler.cpp b/processor/spc700/disassembler.cpp index 9c95d2e1..fbbde16e 100644 --- a/processor/spc700/disassembler.cpp +++ b/processor/spc700/disassembler.cpp @@ -1,4 +1,4 @@ -string SPC700::disassemble_opcode(uint16 addr) { +string SPC700::disassemble_opcode(uint16 addr, bool p) { auto read = [&](uint16 addr) -> uint8 { return disassembler_read(addr); }; @@ -11,7 +11,7 @@ string SPC700::disassemble_opcode(uint16 addr) { auto a = [&] { return hex<4>((read(addr + 1) << 0) + (read(addr + 2) << 8)); }; auto b = [&](unsigned n) { return hex<2>(read(addr + 1 + n)); }; auto r = [&](unsigned r, unsigned n = 0) { return hex<4>(addr + r + (int8)read(addr + 1 + n)); }; - auto dp = [&](unsigned n) { return hex<3>((regs.p.p << 8) + read(addr + 1 + n)); }; + auto dp = [&](unsigned n) { return hex<3>((p << 8) + read(addr + 1 + n)); }; auto ab = [&] { unsigned n = (read(addr + 1) << 0) + (read(addr + 2) << 8); return string{ hex<4>(n & 0x1fff), ":", hex<1>(n >> 13) }; diff --git a/processor/spc700/spc700.hpp b/processor/spc700/spc700.hpp index 5ff3a40a..68ee7a85 100644 --- a/processor/spc700/spc700.hpp +++ b/processor/spc700/spc700.hpp @@ -19,7 +19,7 @@ struct SPC700 { uint8 opcode; void serialize(serializer&); - string disassemble_opcode(uint16 addr); + string disassemble_opcode(uint16 addr, bool p); protected: uint8 op_adc(uint8, uint8); diff --git a/sfc/cheat/cheat.cpp b/sfc/cheat/cheat.cpp index 9dcdd54f..8eee902e 100644 --- a/sfc/cheat/cheat.cpp +++ b/sfc/cheat/cheat.cpp @@ -17,16 +17,16 @@ void Cheat::append(unsigned addr, unsigned comp, unsigned data) { codes.append({addr, comp, data}); } -optional Cheat::find(unsigned addr, unsigned comp) { +maybe Cheat::find(unsigned addr, unsigned comp) { //WRAM mirroring: $00-3f,80-bf:0000-1fff -> $7e:0000-1fff if((addr & 0x40e000) == 0x000000) addr = 0x7e0000 | (addr & 0x1fff); for(auto& code : codes) { if(code.addr == addr && (code.comp == Unused || code.comp == comp)) { - return {true, code.data}; + return code.data; } } - return false; + return nothing; } } diff --git a/sfc/cheat/cheat.hpp b/sfc/cheat/cheat.hpp index c1cb490a..43f2d05c 100644 --- a/sfc/cheat/cheat.hpp +++ b/sfc/cheat/cheat.hpp @@ -11,7 +11,7 @@ struct Cheat { void reset(); void append(unsigned addr, unsigned data); void append(unsigned addr, unsigned comp, unsigned data); - optional find(unsigned addr, unsigned comp); + maybe find(unsigned addr, unsigned comp); }; extern Cheat cheat; diff --git a/sfc/cpu/cpu.cpp b/sfc/cpu/cpu.cpp index 1f01a9d0..4aa60e8e 100644 --- a/sfc/cpu/cpu.cpp +++ b/sfc/cpu/cpu.cpp @@ -86,12 +86,6 @@ void CPU::enter() { void CPU::op_step() { debugger.op_exec(regs.pc.d); - if(interface->tracer.open()) { - char text[4096]; - disassemble_opcode(text); - interface->tracer.print(text, "\n"); - } - (this->*opcode_table[op_readpc()])(); } diff --git a/sfc/interface/interface.cpp b/sfc/interface/interface.cpp index 41d1f763..66b7c643 100644 --- a/sfc/interface/interface.cpp +++ b/sfc/interface/interface.cpp @@ -270,7 +270,6 @@ void Interface::save(unsigned id, const stream& stream) { void Interface::unload() { save(); cartridge.unload(); - tracerEnable(false); } void Interface::connect(unsigned port, unsigned device) { @@ -341,38 +340,6 @@ void Interface::paletteUpdate(PaletteMode mode) { video.generate_palette(mode); } -bool Interface::tracerEnable(bool trace) { - string pathname = {path(group(ID::ROM)), "debug/"}; - if(trace == true) directory::create(pathname); - - if(trace == true && !tracer.open()) { - for(unsigned n = 0; n <= 999; n++) { - string filename = {pathname, "trace-", format<3, '0'>(n), ".log"}; - if(file::exists(filename)) continue; - tracer.open(filename, file::mode::write); - return true; - } - } - - if(trace == false && tracer.open()) { - tracer.close(); - return true; - } - - return false; -} - -void Interface::exportMemory() { - string pathname = {path(group(ID::ROM)), "debug/"}; - directory::create(pathname); - - file::write({pathname, "work.ram"}, cpu.wram, 128 * 1024); - file::write({pathname, "video.ram"}, ppu.vram, 64 * 1024); - file::write({pathname, "sprite.ram"}, ppu.oam, 544); - file::write({pathname, "palette.ram"}, ppu.cgram, 512); - file::write({pathname, "apu.ram"}, smp.apuram, 64 * 1024); -} - Interface::Interface() { interface = this; system.init(); diff --git a/sfc/interface/interface.hpp b/sfc/interface/interface.hpp index 8494ef63..e4f0f6dc 100644 --- a/sfc/interface/interface.hpp +++ b/sfc/interface/interface.hpp @@ -117,13 +117,8 @@ struct Interface : Emulator::Interface { void paletteUpdate(PaletteMode mode); - //debugger functions - bool tracerEnable(bool); - void exportMemory(); - Interface(); - file tracer; vector device; }; diff --git a/target-higan/input/hotkeys.cpp b/target-higan/input/hotkeys.cpp index d73ab27a..0df72552 100644 --- a/target-higan/input/hotkeys.cpp +++ b/target-higan/input/hotkeys.cpp @@ -129,28 +129,6 @@ void InputManager::appendHotkeys() { }; } - { - auto hotkey = new HotkeyInput; - hotkey->name = "Toggle Tracer"; - hotkey->mapping = "None"; - - hotkey->press = [&] { - utility->tracerToggle(); - }; - } - - { - auto hotkey = new HotkeyInput; - hotkey->name = "Export Memory"; - hotkey->mapping = "None"; - - hotkey->press = [&] { - if(program->active == nullptr) return; - system().exportMemory(); - utility->showMessage("Memory exported"); - }; - } - Configuration::Node node; for(auto& hotkey : hotkeyMap) { node.append(hotkey->mapping, string{hotkey->name}.replace(" ", "")); diff --git a/target-higan/utility/utility.cpp b/target-higan/utility/utility.cpp index 460cf81e..2645092a 100644 --- a/target-higan/utility/utility.cpp +++ b/target-higan/utility/utility.cpp @@ -101,7 +101,6 @@ void Utility::load() { void Utility::unload() { if(program->active == nullptr) return; - if(tracerEnable) tracerToggle(); cheatEditor->save({pathname[0], "cheats.bml"}); stateManager->save({pathname[0], "higan/states.bsa"}, 1); @@ -139,16 +138,6 @@ void Utility::loadState(unsigned slot) { showMessage({"Loaded from slot ", slot}); } -void Utility::tracerToggle() { - if(program->active == nullptr) return; - tracerEnable = !tracerEnable; - bool result = system().tracerEnable(tracerEnable); - if( tracerEnable && result) return utility->showMessage("Tracer activated"); - if( tracerEnable && !result) return tracerEnable = false, utility->showMessage("Unable to activate tracer"); - if(!tracerEnable && result) return utility->showMessage("Tracer deactivated"); - if(!tracerEnable && !result) return utility->showMessage("Unable to deactivate tracer"); -} - void Utility::synchronizeDSP() { if(program->active == nullptr) return; @@ -323,8 +312,3 @@ string Utility::libraryPath() { if(path.endsWith("/") == false) path.append("/"); return path; } - -Utility::Utility() { - tracerEnable = false; - statusTime = 0; -} diff --git a/target-higan/utility/utility.hpp b/target-higan/utility/utility.hpp index 82490808..5b3fb92c 100644 --- a/target-higan/utility/utility.hpp +++ b/target-higan/utility/utility.hpp @@ -17,8 +17,6 @@ struct Utility { void saveState(unsigned slot); void loadState(unsigned slot); - void tracerToggle(); - void synchronizeDSP(); void synchronizeRuby(); void updatePalette(); @@ -32,16 +30,13 @@ struct Utility { string libraryPath(); - Utility(); - lstring path; lstring pathname; private: - bool tracerEnable; string statusText; string statusMessage; - time_t statusTime; + time_t statusTime = 0; }; extern Utility* utility; diff --git a/target-loki/debugger/debugger.cpp b/target-loki/debugger/debugger.cpp index 3fb2ede8..f1947680 100644 --- a/target-loki/debugger/debugger.cpp +++ b/target-loki/debugger/debugger.cpp @@ -20,37 +20,30 @@ Debugger::Debugger() { void Debugger::load() { directory::create({interface->pathname, "loki/"}); - usageCPU = new uint8[0x1000000](); - usageAPU = new uint8[0x10000](); + cpuUsage = new uint8[0x1000000](); + apuUsage = new uint8[0x10000](); file fp; - if(fp.open({interface->pathname, "loki/usage.cpu.bin"}, file::mode::read)) { - if(fp.size() == 0x1000000) fp.read(usageCPU, 0x1000000); + if(fp.open({interface->pathname, "loki/cpu.usage.map"}, file::mode::read)) { + if(fp.size() == 0x1000000) fp.read(cpuUsage, 0x1000000); fp.close(); } - if(fp.open({interface->pathname, "loki/usage.apu.bin"}, file::mode::read)) { - if(fp.size() == 0x10000) fp.read(usageAPU, 0x10000); + if(fp.open({interface->pathname, "loki/apu.usage.map"}, file::mode::read)) { + if(fp.size() == 0x10000) fp.read(apuUsage, 0x10000); 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(); - } - if(fp.open({interface->pathname, "loki/usage.apu.bin"}, file::mode::write)) { - fp.write(usageAPU, 0x10000); - fp.close(); - } - delete[] usageCPU; - delete[] usageAPU; - usageCPU = nullptr; - usageAPU = nullptr; + if(cpuTracerFile.open()) cpuTracerFile.close(); + if(smpTracerFile.open()) smpTracerFile.close(); + file::write({interface->pathname, "loki/cpu.usage.map"}, cpuUsage, 0x1000000); + file::write({interface->pathname, "loki/apu.usage.map"}, apuUsage, 0x10000); + delete[] cpuUsage; + delete[] apuUsage; + cpuUsage = nullptr; + apuUsage = nullptr; } void Debugger::main() { @@ -68,10 +61,14 @@ void Debugger::run() { void Debugger::stop() { running = false; - cpuRunFor.reset(); - cpuRunTo.reset(); - cpuStepFor.reset(); - cpuStepTo.reset(); + cpuRunFor = nothing; + cpuRunTo = nothing; + cpuStepFor = nothing; + cpuStepTo = nothing; + smpRunFor = nothing; + smpRunTo = nothing; + smpStepFor = nothing; + smpStepTo = nothing; } void Debugger::leave() { @@ -86,10 +83,11 @@ bool Debugger::breakpointTest(Source source, Breakpoint::Mode mode, unsigned add if(bp.mode != mode) continue; if(bp.addr != addr) continue; if(bp.mode != Breakpoint::Mode::Execute && bp.data && bp.data() != data) continue; - echo("Breakpoint #", n, " hit"); - if(bp.mode == Breakpoint::Mode::Read ) echo("; read ", hex<2>(data)); - if(bp.mode == Breakpoint::Mode::Write) echo("; wrote ", hex<2>(data)); - echo("; triggered: ", ++bp.triggered, "\n"); + string output = {"Breakpoint #", n, " hit"}; + if(bp.mode == Breakpoint::Mode::Read ) output.append("; read ", hex<2>(data)); + if(bp.mode == Breakpoint::Mode::Write) output.append("; wrote ", hex<2>(data)); + output.append("; triggered: ", ++bp.triggered); + echo(output, "\n"); return true; } return false; @@ -98,28 +96,30 @@ bool Debugger::breakpointTest(Source source, Breakpoint::Mode mode, unsigned add string Debugger::cpuDisassemble() { char text[4096]; SFC::cpu.disassemble_opcode(text); - return {text, " I:", (unsigned)SFC::cpu.field(), " V:", format<3>(SFC::cpu.vcounter()), " H:", format<4>(SFC::cpu.hcounter())}; + return {text, " F:", (unsigned)SFC::cpu.field(), " V:", format<3>(SFC::cpu.vcounter()), " H:", format<4>(SFC::cpu.hcounter())}; } 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, " I:", (unsigned)SFC::cpu.field(), " V:", format<3>(SFC::cpu.vcounter()), " H:", format<4>(SFC::cpu.hcounter())}; + return {text, " F:", (unsigned)SFC::cpu.field(), " V:", format<3>(SFC::cpu.vcounter()), " H:", format<4>(SFC::cpu.hcounter())}; } 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; + cpuUsage[addr] |= Usage::Execute; + if(SFC::cpu.regs.e == 0) cpuUsage[addr] &= ~Usage::FlagE; + if(SFC::cpu.regs.p.m == 0) cpuUsage[addr] &= ~Usage::FlagM; + if(SFC::cpu.regs.p.x == 0) cpuUsage[addr] &= ~Usage::FlagX; + if(SFC::cpu.regs.e == 1) cpuUsage[addr] |= Usage::FlagE; + if(SFC::cpu.regs.p.m == 1) cpuUsage[addr] |= Usage::FlagM; + if(SFC::cpu.regs.p.x == 1) cpuUsage[addr] |= Usage::FlagX; - if(tracerFile.open()) { - if(!tracerMask || tracerMask[addr] == false) { - if(tracerMask) tracerMask[addr] = true; - tracerFile.print(cpuDisassemble(), "\n"); + cpuInstructionCounter++; + + if(cpuTracerFile.open()) { + if(!cpuTracerMask || cpuTracerMask[addr] == false) { + if(cpuTracerMask) cpuTracerMask[addr] = true; + cpuTracerFile.print(cpuDisassemble(), "\n"); } } @@ -154,12 +154,12 @@ void Debugger::cpuExec(uint24 addr) { } void Debugger::cpuRead(uint24 addr, uint8 data) { - usageCPU[addr] |= Usage::Read; + cpuUsage[addr] |= Usage::Read; if(breakpointTest(Source::CPU, Breakpoint::Mode::Read, addr, data)) leave(); } void Debugger::cpuWrite(uint24 addr, uint8 data) { - usageCPU[addr] |= Usage::Write; + cpuUsage[addr] |= Usage::Write; if(breakpointTest(Source::CPU, Breakpoint::Mode::Write, addr, data)) leave(); } @@ -182,21 +182,30 @@ void Debugger::echoBreakpoints() { } } -void Debugger::echoDisassemble(unsigned addr, signed size) { - if(!(usageCPU[addr] & Usage::Execute)) return echo("No usage data available for cpu/", hex<6>(addr), "\n"); +void Debugger::echoDisassemble(Source source, unsigned addr, signed size) { + if(source != Source::CPU && source != Source::SMP) return; + const unsigned maximumDisplacement = (source == Source::CPU ? 5 : 4); //maximum opcode length + uint8* usage = (source == Source::CPU ? cpuUsage : apuUsage); + if(!(usage[addr] & Usage::Execute)) return echo("No usage data available for ", sourceName(source), "/", hex<6>(addr), "\n"); while(size > 0) { - string text = cpuDisassemble(addr, usageCPU[addr] & Usage::FlagE, usageCPU[addr] & Usage::FlagM, usageCPU[addr] & Usage::FlagX); + string text; + if(source == Source::CPU) { + text = cpuDisassemble(addr, usage[addr] & Usage::FlagE, usage[addr] & Usage::FlagM, usage[addr] & Usage::FlagX); + } + if(source == Source::SMP) { + text = smpDisassemble(addr, usage[addr] & Usage::FlagP); + } text.resize(20); //remove register information 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; + while(displacement < maximumDisplacement) { //maximum opcode length is four bytes + if(usage[addr + displacement] & Usage::Execute) break; displacement++; } - if(displacement >= 5) { + if(displacement >= maximumDisplacement) { echo("...\n"); return; } @@ -205,6 +214,7 @@ void Debugger::echoDisassemble(unsigned addr, signed size) { } void Debugger::echoHex(Source source, unsigned addr, signed size) { + if(memorySize(source) == 0) return; //not a valid memory pool while(size > 0) { string hexdata, asciidata; for(unsigned n = 0; n < 16; n++) { @@ -245,6 +255,10 @@ uint8 Debugger::memoryRead(Source source, unsigned addr) { return SFC::smp.apuram[addr & 0xffff]; } + if(source == Source::WRAM) { + return SFC::cpu.wram[addr & 0x1ffff]; + } + if(source == Source::VRAM) { return SFC::ppu.vram[addr & 0xffff]; } @@ -264,11 +278,12 @@ unsigned Debugger::memorySize(Source source) { switch(source) { case Source::CPU: return 0x1000000; case Source::APU: return 0x10000; + case Source::WRAM: return 0x20000; case Source::VRAM: return 0x10000; case Source::OAM: return 544; case Source::CGRAM: return 512; } - return 1; + return 0; } void Debugger::memoryWrite(Source source, unsigned addr, uint8 data) { @@ -282,6 +297,11 @@ void Debugger::memoryWrite(Source source, unsigned addr, uint8 data) { return; } + if(source == Source::WRAM) { + SFC::cpu.wram[addr & 0x1ffff] = data; + return; + } + if(source == Source::VRAM) { SFC::ppu.vram[addr & 0xffff] = data; return; @@ -324,22 +344,66 @@ void Debugger::ppuVramWrite(uint16 addr, uint8 data) { if(breakpointTest(Source::VRAM, Breakpoint::Mode::Write, addr, data)) leave(); } +string Debugger::smpDisassemble() { + return SFC::smp.disassemble_opcode(SFC::smp.regs.pc, SFC::smp.regs.p.p); +} + +string Debugger::smpDisassemble(uint16 addr, bool p) { + return SFC::smp.disassemble_opcode(addr, p); +} + void Debugger::smpExec(uint16 addr) { - usageAPU[addr] |= Usage::Execute; + apuUsage[addr] |= Usage::Execute; + if(SFC::smp.regs.p.p == 0) apuUsage[addr] &= ~Usage::FlagP; + if(SFC::smp.regs.p.p == 1) apuUsage[addr] |= Usage::FlagP; + + smpInstructionCounter++; + + if(smpTracerFile.open()) { + if(!smpTracerMask || smpTracerMask[addr] == false) { + if(smpTracerMask) smpTracerMask[addr] = true; + smpTracerFile.print(smpDisassemble(), "\n"); + } + } if(breakpointTest(Source::SMP, Breakpoint::Mode::Execute, addr)) { - leave(); + echo(smpDisassemble(), "\n"); + return leave(); + } + + if(smpRunFor) { + if(--smpRunFor() == 0) { + echo(smpDisassemble(), "\n"); + return leave(); + } + } + + if(smpRunTo) { + if(addr == smpRunTo()) { + echo(smpDisassemble(), "\n"); + return leave(); + } + } + + if(smpStepFor) { + echo(smpDisassemble(), "\n"); + if(--smpStepFor() == 0) return leave(); + } + + if(smpStepTo) { + echo(smpDisassemble(), "\n"); + if(addr == smpStepTo()) return leave(); } } void Debugger::smpRead(uint16 addr, uint8 data) { - usageAPU[addr] |= Usage::Read; + apuUsage[addr] |= Usage::Read; if(breakpointTest(Source::SMP, Breakpoint::Mode::Read, addr, data)) leave(); if(breakpointTest(Source::APU, Breakpoint::Mode::Read, addr, data)) leave(); } void Debugger::smpWrite(uint16 addr, uint8 data) { - usageAPU[addr] |= Usage::Write; + apuUsage[addr] |= Usage::Write; if(breakpointTest(Source::SMP, Breakpoint::Mode::Write, addr, data)) leave(); if(breakpointTest(Source::APU, Breakpoint::Mode::Write, addr, data)) leave(); } @@ -351,9 +415,43 @@ string Debugger::sourceName(Source source) { case Source::PPU: return "ppu"; case Source::DSP: return "dsp"; case Source::APU: return "apu"; + case Source::WRAM: return "wram"; case Source::VRAM: return "vram"; case Source::OAM: return "oam"; case Source::CGRAM: return "cgram"; } return "none"; } + +void Debugger::tracerDisable(Source source) { + if(source != Source::CPU && source != Source::SMP) return; + file& tracerFile = (source == Source::CPU ? cpuTracerFile : smpTracerFile); + if(tracerFile.open() == false) return; + tracerFile.close(); + echo(sourceName(source).upper(), " tracer disabled\n"); +} + +void Debugger::tracerEnable(Source source, string filename) { + if(source != Source::CPU && source != Source::SMP) return; + file& tracerFile = (source == Source::CPU ? cpuTracerFile : smpTracerFile); + if(tracerFile.open() == true) return; + if(tracerFile.open(filename, file::mode::write)) { + echo(sourceName(source).upper(), " tracer enabled\n"); + } +} + +void Debugger::tracerMaskDisable(Source source) { + if(source != Source::CPU && source != Source::SMP) return; + bitvector& tracerMask = (source == Source::CPU ? cpuTracerMask : smpTracerMask); + tracerMask.reset(); + echo(sourceName(source).upper(), " tracer mask disabled\n"); +} + +void Debugger::tracerMaskEnable(Source source) { + if(source != Source::CPU && source != Source::SMP) return; + bitvector& tracerMask = (source == Source::CPU ? cpuTracerMask : smpTracerMask); + unsigned size = (source == Source::CPU ? 0x1000000 : 0x10000); + tracerMask.resize(size); + tracerMask.clear(); + echo(sourceName(source).upper(), " tracer mask enabled\n"); +} diff --git a/target-loki/debugger/debugger.hpp b/target-loki/debugger/debugger.hpp index 7138e9e2..647b2993 100644 --- a/target-loki/debugger/debugger.hpp +++ b/target-loki/debugger/debugger.hpp @@ -1,11 +1,11 @@ struct Debugger { - enum class Source : unsigned { CPU, SMP, PPU, DSP, APU, VRAM, OAM, CGRAM }; + enum class Source : unsigned { CPU, SMP, PPU, DSP, APU, WRAM, VRAM, OAM, CGRAM }; struct Breakpoint { Source source = Source::CPU; enum class Mode : unsigned { Disabled, Read, Write, Execute } mode = Mode::Disabled; unsigned addr = 0; - optional data = false; + maybe data; unsigned triggered = 0; //counter for number of times breakpoint was hit }; @@ -19,8 +19,9 @@ struct Debugger { FlagM = 0x10, FlagX = 0x20, //APU - DspRead = 0x08, - DspWrite = 0x10, + FlagP = 0x08, + DspRead = 0x10, + DspWrite = 0x20, }; }; @@ -41,7 +42,7 @@ struct Debugger { void cpuRead(uint24 addr, uint8 data); void cpuWrite(uint24 addr, uint8 data); void echoBreakpoints(); - void echoDisassemble(unsigned addr, signed size); + void echoDisassemble(Source source, unsigned addr, signed size); void echoHex(Source source, unsigned addr, signed size); void memoryExport(Source source, string filename); uint8 memoryRead(Source source, unsigned addr); @@ -53,22 +54,36 @@ struct Debugger { void ppuOamWrite(uint16 addr, uint8 data); void ppuVramRead(uint16 addr, uint8 data); void ppuVramWrite(uint16 addr, uint8 data); + string smpDisassemble(); + string smpDisassemble(uint16 addr, bool p); void smpExec(uint16 addr); void smpRead(uint16 addr, uint8 data); void smpWrite(uint16 addr, uint8 data); string sourceName(Source source); + void tracerDisable(Source source); + void tracerEnable(Source source, string filename); + void tracerMaskDisable(Source source); + void tracerMaskEnable(Source source); bool running = false; + uint8* apuUsage = nullptr; vector breakpoints; - optional cpuRunFor = false; - optional cpuRunTo = false; - optional cpuStepFor = false; - optional cpuStepTo = false; - file tracerFile; - bitvector tracerMask; - uint8* usageCPU = nullptr; - uint8* usageAPU = nullptr; + unsigned cpuInstructionCounter = 0; + maybe cpuRunFor; + maybe cpuRunTo; + maybe cpuStepFor; + maybe cpuStepTo; + file cpuTracerFile; + bitvector cpuTracerMask; + uint8* cpuUsage = nullptr; + unsigned smpInstructionCounter = 0; + maybe smpRunFor; + maybe smpRunTo; + maybe smpStepFor; + maybe smpStepTo; + file smpTracerFile; + bitvector smpTracerMask; }; extern Debugger* debugger; diff --git a/target-loki/terminal/terminal.cpp b/target-loki/terminal/terminal.cpp index 31087629..c77f4d00 100644 --- a/target-loki/terminal/terminal.cpp +++ b/target-loki/terminal/terminal.cpp @@ -24,6 +24,7 @@ void Terminal::command(string t) { if(t.beginsWith("ppu/" )) { source = Debugger::Source::PPU; t.ltrim<1>("ppu/" ); } if(t.beginsWith("dsp/" )) { source = Debugger::Source::DSP; t.ltrim<1>("dsp/" ); } if(t.beginsWith("apu/" )) { source = Debugger::Source::APU; t.ltrim<1>("apu/" ); } + if(t.beginsWith("wram/" )) { source = Debugger::Source::WRAM; t.ltrim<1>("wram/" ); } if(t.beginsWith("vram/" )) { source = Debugger::Source::VRAM; t.ltrim<1>("vram/" ); } if(t.beginsWith("oam/" )) { source = Debugger::Source::OAM; t.ltrim<1>("oam/" ); } if(t.beginsWith("cgram/")) { source = Debugger::Source::CGRAM; t.ltrim<1>("cgram/"); } @@ -56,7 +57,7 @@ void Terminal::command(string t) { 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])}; + if(argc >= 3) bp.data = (uint8_t)hex(args[2]); debugger->breakpoints.append(bp); debugger->echoBreakpoints(); return; @@ -81,13 +82,25 @@ void Terminal::command(string t) { return; } + if(s == "counter") { + if(source == Debugger::Source::CPU) echo("CPU instructions executed: ", debugger->cpuInstructionCounter, "\n"); + if(source == Debugger::Source::SMP) echo("SMP instructions executed: ", debugger->smpInstructionCounter, "\n"); + return; + } + + if(s == "counter.reset") { + if(source == Debugger::Source::CPU) { echo("CPU instruction counter reset\n"); debugger->cpuInstructionCounter = 0; } + if(source == Debugger::Source::SMP) { echo("SMP instruction counter reset\n"); debugger->smpInstructionCounter = 0; } + return; + } + if(s == "disassemble" && argc >= 1 && argc <= 2) { - debugger->echoDisassemble(hex(args[0]), argc == 2 ? decimal(args[1]) : 16); + debugger->echoDisassemble(source, hex(args[0]), argc == 2 ? decimal(args[1]) : 16); return; } if(s == "export" && argc <= 1) { - string filename = {debugger->sourceName(source), "-", string::datetime().transform(" :", "--"), ".bin"}; + string filename = {debugger->sourceName(source), "-", string::datetime().transform(" :", "--"), ".ram"}; if(argc >= 1) filename = args[0]; string pathname = {interface->pathname, "loki/", filename}; debugger->memoryExport(source, pathname); @@ -118,68 +131,65 @@ void Terminal::command(string t) { if(s == "run.for" && argc == 1) { debugger->run(); - debugger->cpuRunFor = {true, (unsigned)decimal(args[0])}; + if(source == Debugger::Source::CPU) debugger->cpuRunFor = (unsigned)decimal(args[0]); + if(source == Debugger::Source::SMP) debugger->smpRunFor = (unsigned)decimal(args[0]); return; } if(s == "run.to" && argc == 1) { debugger->run(); - debugger->cpuRunTo = {true, (unsigned)hex(args[0])}; + if(source == Debugger::Source::CPU) debugger->cpuRunTo = (unsigned)hex(args[0]); + if(source == Debugger::Source::SMP) debugger->smpRunTo = (unsigned)hex(args[0]); return; } if(s == "step" && argc == 0) { debugger->run(); - debugger->cpuStepFor = {true, 1u}; + if(source == Debugger::Source::CPU) debugger->cpuStepFor = 1u; + if(source == Debugger::Source::SMP) debugger->smpStepFor = 1u; return; } if(s == "step.for" && argc == 1) { debugger->run(); - debugger->cpuStepFor = {true, (unsigned)decimal(args[0])}; + if(source == Debugger::Source::CPU) debugger->cpuStepFor = (unsigned)decimal(args[0]); + if(source == Debugger::Source::SMP) debugger->smpStepFor = (unsigned)decimal(args[0]); return; } if(s == "step.to" && argc == 1) { debugger->run(); - debugger->cpuStepTo = {true, (unsigned)hex(args[0])}; + if(source == Debugger::Source::CPU) debugger->cpuStepTo = (unsigned)hex(args[0]); + if(source == Debugger::Source::SMP) debugger->smpStepTo = (unsigned)hex(args[0]); 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/", filename}; - if(debugger->tracerFile.open(pathname, file::mode::write)) { - echo("Tracer enabled\n"); - } - } + string filename = {debugger->sourceName(source), "-trace-", string::datetime().transform(" :", "--"), ".log"}; + if(argc >= 1) filename = args[0]; + string pathname = {interface->pathname, "loki/", filename}; + debugger->tracerEnable(source, pathname); return; } if(s == "tracer.disable") { - if(debugger->tracerFile.open() == true) { - debugger->tracerFile.close(); - echo("Tracer disabled\n"); - } + debugger->tracerDisable(source); return; } - if(s == "tracer.mask" && argc == 1) { - if(args[0] != "false") { - debugger->tracerMask.resize(0x1000000); - debugger->tracerMask.clear(); - echo("Tracer mask enabled\n"); - } else { - debugger->tracerMask.reset(); - echo("Tracer mask disabled\n"); - } + if(s == "tracer.mask.enable") { + debugger->tracerMaskEnable(source); + return; + } + + if(s == "tracer.mask.disable") { + debugger->tracerMaskDisable(source); return; } if(s == "usage.reset") { - memset(debugger->usageCPU, 0, 0x1000000); + if(source == Debugger::Source::CPU) memset(debugger->cpuUsage, 0x00, 0x1000000); + if(source == Debugger::Source::APU) memset(debugger->apuUsage, 0x00, 0x10000); return; }