| @@ -0,0 +1,17 @@ | ||
| #include "symbol_file_interface.hpp" | ||
|
|
||
| class SymbolMap; | ||
|
|
||
| class ViceLabelFile : public SymbolFileInterface { | ||
| public: | ||
| ViceLabelFile() {} | ||
| virtual ~ViceLabelFile() {} | ||
|
|
||
| const char *getName() const; | ||
| const char *getDescription() const; | ||
|
|
||
| int32_t scoreReadString(const nall::lstring &rows) const; | ||
| bool read(const nall::lstring &rows, SymbolMap *map) const; | ||
|
|
||
| uint32_t getFeatures() const; | ||
| }; |
| @@ -0,0 +1,136 @@ | ||
| #include "wla_symbol_file.hpp" | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| const char *WlaSymbolFile::getName() const { | ||
| return "WLA symbol file"; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| const char *WlaSymbolFile::getDescription() const { | ||
| return "WLA-Assembler symbol file format"; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| uint32_t WlaSymbolFile::getFeatures() const { | ||
| return 0 | ||
| | SymbolFileInterface::Readable | ||
| | SymbolFileInterface::Symbols | ||
| | SymbolFileInterface::Files | ||
| | SymbolFileInterface::LineMap | ||
| ; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| string WlaSymbolFile::filteredRow(const string &input) const { | ||
| string row(input); | ||
|
|
||
| row.trim("\r"); | ||
| optional<unsigned> comment = row.position(";"); | ||
| if (comment) { | ||
| unsigned index = comment(); | ||
| if (index == 0) { | ||
| return ""; | ||
| } | ||
| row = nall::substr(row, 0, index); | ||
| } | ||
|
|
||
| row.trim(" "); | ||
| return row; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| int32_t WlaSymbolFile::scoreReadString(const lstring &rows) const { | ||
| if (rows.size() == 0) { | ||
| return -1; | ||
| } | ||
|
|
||
| bool isInLabelsSection = false; | ||
|
|
||
| for (uint32_t i=0; i<rows.size(); i++) { | ||
| const string &row = filteredRow(rows[i]); | ||
| if (row.length() == 0) { | ||
| continue; | ||
| } | ||
|
|
||
| if (row == "[labels]") { | ||
| isInLabelsSection = true; | ||
| } else if (row[0] == '[') { | ||
| isInLabelsSection = false; | ||
| } else if (isInLabelsSection) { | ||
| uint32_t address = (nall::hex(nall::substr(row, 0, 2)) << 16) | nall::hex(nall::substr(row, 3, 4)); | ||
|
|
||
| if (address > 0) { | ||
| return 1; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return -1; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| bool WlaSymbolFile::read(const lstring &rows, SymbolMap *map) const { | ||
| enum Section { | ||
| SECTION_UNKNOWN, | ||
| SECTION_LABELS, | ||
| SECTION_COMMENTS, | ||
| SECTION_DEBUG, | ||
| SECTION_FILES, | ||
| SECTION_SOURCEMAP, | ||
| }; | ||
|
|
||
| Section section = SECTION_LABELS; | ||
| for (int i=0; i<rows.size(); i++) { | ||
| string row = filteredRow(rows[i]); | ||
| if (row.length() == 0) { | ||
| continue; | ||
| } | ||
|
|
||
| if (row[0] == '[') { | ||
| if (row == "[labels]") { section = SECTION_LABELS; } | ||
| else if (row == "[comments]") { section = SECTION_COMMENTS; } | ||
| else if (row == "[addr-to-line-mapping]") { section = SECTION_SOURCEMAP; } | ||
| else if (row == "[source-files]") { section = SECTION_FILES; } | ||
|
|
||
| else { section = SECTION_UNKNOWN; } | ||
| continue; | ||
| } | ||
|
|
||
| switch (section) { | ||
| case SECTION_LABELS: | ||
| map->addLocation( | ||
| (nall::hex(nall::substr(row, 0, 2)) << 16) | nall::hex(nall::substr(row, 3, 4)), | ||
| nall::substr(row, 8, row.length() - 8) | ||
| ); | ||
| break; | ||
|
|
||
| case SECTION_COMMENTS: | ||
| map->addComment( | ||
| (nall::hex(nall::substr(row, 0, 2)) << 16) | nall::hex(nall::substr(row, 3, 4)), | ||
| nall::substr(row, 8, row.length() - 8) | ||
| ); | ||
| break; | ||
|
|
||
| case SECTION_SOURCEMAP: | ||
| map->addSourceLine( | ||
| (nall::hex(nall::substr(row, 0, 2)) << 16) | nall::hex(nall::substr(row, 3, 4)), | ||
| nall::hex(nall::substr(row, 8, 4)), | ||
| nall::hex(nall::substr(row, 13, 8)) | ||
| ); | ||
| break; | ||
|
|
||
| case SECTION_FILES: | ||
| map->addSourceFile( | ||
| nall::hex(nall::substr(row, 0, 4)), | ||
| nall::hex(nall::substr(row, 5, 8)), | ||
| nall::substr(row, 14, row.length() - 14) | ||
| ); | ||
| break; | ||
|
|
||
| case SECTION_UNKNOWN: | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } |
| @@ -0,0 +1,19 @@ | ||
| #include "symbol_file_interface.hpp" | ||
|
|
||
| class SymbolMap; | ||
|
|
||
| class WlaSymbolFile : public SymbolFileInterface { | ||
| public: | ||
| WlaSymbolFile() {} | ||
| virtual ~WlaSymbolFile() {} | ||
|
|
||
| const char *getName() const; | ||
| const char *getDescription() const; | ||
|
|
||
| int32_t scoreReadString(const nall::lstring &rows) const; | ||
| bool read(const nall::lstring &rows, SymbolMap *map) const; | ||
|
|
||
| nall::string filteredRow(const nall::string &input) const; | ||
|
|
||
| uint32_t getFeatures() const; | ||
| }; |
| @@ -0,0 +1,72 @@ | ||
| #include "symbol_file_adapters.hpp" | ||
|
|
||
| #include "adapters/fma_symbol_file.cpp" | ||
| #include "adapters/wla_symbol_file.cpp" | ||
| #include "adapters/vice_label_file.cpp" | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| SymbolFileAdapters::SymbolFileAdapters() { | ||
| registerAdapter(new FmaSymbolFile()); | ||
| registerAdapter(new WlaSymbolFile()); | ||
| registerAdapter(new ViceLabelFile()); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolFileAdapters::registerAdapter(SymbolFileInterface* adapter) { | ||
| adapters.append(adapter); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| SymbolFileInterface *SymbolFileAdapters::findBestAdapter(const nall::lstring &rows) { | ||
| SymbolFileInterface *current = NULL; | ||
| int32_t currentScore = -1; | ||
|
|
||
| for (uint32_t i=0; i<adapters.size(); i++) { | ||
| SymbolFileInterface *adapter = adapters[i]; | ||
| uint32_t features = adapter->getFeatures(); | ||
|
|
||
| if ((features & SymbolFileInterface::Readable) == 0) { | ||
| continue; | ||
| } | ||
|
|
||
| int32_t score = adapter->scoreReadString(rows); | ||
| if (score > currentScore) { | ||
| currentScore = score; | ||
| current = adapter; | ||
| } | ||
| } | ||
|
|
||
| return current; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| SymbolFileInterface *SymbolFileAdapters::fetchAdapter(uint32_t requiredFeatures, uint32_t optionalFeatures) { | ||
| SymbolFileInterface *current = NULL; | ||
| uint32_t currentScore = 0; | ||
|
|
||
| for (uint32_t i=0; i<adapters.size(); i++) { | ||
| SymbolFileInterface *adapter = adapters[i]; | ||
| uint32_t features = adapter->getFeatures(); | ||
| uint32_t score = 0; | ||
|
|
||
| if ((features & requiredFeatures) != requiredFeatures) { | ||
| continue; | ||
| } | ||
|
|
||
| features &= optionalFeatures; | ||
| for (; features; features >>= 1) { | ||
| if (features & 1) { | ||
| score++; | ||
| } | ||
| } | ||
|
|
||
| if (score > currentScore || current == NULL) { | ||
| current = adapter; | ||
| currentScore= score; | ||
| } | ||
| } | ||
|
|
||
| return current; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ |
| @@ -0,0 +1,14 @@ | ||
| class SymbolFileInterface; | ||
|
|
||
| class SymbolFileAdapters { | ||
| public: | ||
| SymbolFileAdapters(); | ||
|
|
||
| void registerAdapter(SymbolFileInterface*); | ||
|
|
||
| SymbolFileInterface *findBestAdapter(const nall::lstring &rows); | ||
| SymbolFileInterface *fetchAdapter(uint32_t requiredFeatures, uint32_t optionalFeatures=0); | ||
|
|
||
| protected: | ||
| nall::linear_vector<SymbolFileInterface*> adapters; | ||
| }; |
| @@ -0,0 +1,282 @@ | ||
| #include "symbol_map.moc" | ||
| #include "symbol_file_adapters.cpp" | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| Symbol Symbols::getSymbol() { | ||
| for (uint32_t i=0; i<symbols.size(); i++) { | ||
| if (symbols[i].isSymbol()) { | ||
| return symbols[i]; | ||
| } | ||
| } | ||
|
|
||
| return Symbol::createInvalid(); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| Symbol Symbols::getComment() { | ||
| for (uint32_t i=0; i<symbols.size(); i++) { | ||
| if (symbols[i].isComment()) { | ||
| return symbols[i]; | ||
| } | ||
| } | ||
|
|
||
| return Symbol::createInvalid(); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| Symbol Symbols::getSourceLine() | ||
| { | ||
| for (uint32_t i = 0; i < symbols.size(); i++) { | ||
| if (symbols[i].isSourceLine()) { | ||
| return symbols[i]; | ||
| } | ||
| } | ||
|
|
||
| return Symbol::createInvalid(); | ||
| } | ||
|
|
||
|
|
||
| // ------------------------------------------------------------------------ | ||
| SymbolMap::SymbolMap() { | ||
| isValid = false; | ||
| adapters = new SymbolFileAdapters(); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| int32_t SymbolMap::getSymbolIndex(uint32_t address) { | ||
| revalidate(); | ||
|
|
||
| int32_t left = 0; | ||
| int32_t right = symbols.size() - 1; | ||
|
|
||
| while (right >= left) { | ||
| uint32_t cur = ((right - left) >> 1) + left; | ||
| uint32_t curaddr = symbols[cur].address; | ||
|
|
||
| if (address < curaddr) { | ||
| right = cur - 1; | ||
| } else if (address > curaddr) { | ||
| left = cur + 1; | ||
| } else { | ||
| return cur; | ||
| } | ||
| } | ||
|
|
||
| return -1; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::addLocation(uint32_t address, const string &name) { | ||
| addSymbol(address, Symbol::createLocation(address, name)); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::addComment(uint32_t address, const string &name) { | ||
| addSymbol(address, Symbol::createComment(address, name)); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::addSymbol(uint32_t address, const Symbol &name) { | ||
| isValid = false; | ||
|
|
||
| int32_t right = symbols.size(); | ||
| for (int32_t i=0; i<right; i++) { | ||
| if (symbols[i].address == address) { | ||
| symbols[i].symbols.append(Symbol(name)); | ||
| return; | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Symbols s; | ||
| s.address = address; | ||
| s.symbols.append(Symbol(name)); | ||
| symbols.append(s); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::addSourceLine(uint32_t address, uint32_t file, uint32_t line) { | ||
| AddressToSourceLine newMapping; | ||
| newMapping.address = address; | ||
| newMapping.file = file; | ||
| newMapping.line = line; | ||
| addressToSourceLineMappings.append(newMapping); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::addSourceFile(uint32_t fileId, uint32_t checksum, const string &filename) { | ||
|
|
||
| string sourceFileData; | ||
| if (fileId < sourceFileLines.size() && sourceFileLines[fileId].size() > 0) { | ||
| // todo | ||
| //debugger->echo(string() << "WARNING: While parsing symbols, file index " << fileId << " appeared for file \"" << sourceFiles[fileId].filename << "\" and \"" << filename << "\". Disassembly listing for either of these may be incorrect or unavailable.<br>"); | ||
| } | ||
| else if (sourceFileData.readfile(filename)) { | ||
| unsigned long local_checksum = crc32_calculate((const uint8_t*)(sourceFileData()), sourceFileData.length()); | ||
| if (checksum != local_checksum) { | ||
| // todo | ||
| //debugger->echo(string() << "WARNING: \"" << sourceFiles[fileId].filename << "\" has been modified since the ROM's symbols were built. Disassembly listing for this file may be incorrect or unavailable.<br>"); | ||
| } | ||
| else { | ||
| sourceFileLines[fileId].split("\n", sourceFileData); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::finishUpdates() { | ||
| // populate sourceline data, now that we have sourceline and sourcefile information | ||
| // make sure symbols and addressToSourceLineMappings are sorted by addr | ||
| if (addressToSourceLineMappings.size() > 0) { | ||
| revalidate(); | ||
| nall::sort(&addressToSourceLineMappings[0], addressToSourceLineMappings.size()); | ||
|
|
||
|
|
||
| uint32_t symbolIndex = 0; | ||
| uint32_t symbolIndexEnd = symbols.size(); | ||
| for (int i = 0; i < addressToSourceLineMappings.size(); ++i) { | ||
| AddressToSourceLine addrToLine = addressToSourceLineMappings[i]; | ||
| string sourceLine; | ||
| if (addrToLine.file < sourceFileLines.size() && addrToLine.line < sourceFileLines[addrToLine.file].size()) { | ||
| sourceLine = sourceFileLines[addrToLine.file][addrToLine.line - 1]; // -1 because line entries are 1-based | ||
| } | ||
| else { | ||
| char hexAddr[9]; | ||
| snprintf(hexAddr, 9, "%.8x", addrToLine.address); | ||
| // todo | ||
| //debugger->echo(string() << "WARNING: Address-to-line mapping for address 0x" << hexAddr << " tried to refer to a file/line location that doesn't exist. File: " << addrToLine.file << ", line: " << addrToLine.line << ".<br>"); | ||
| continue; | ||
| } | ||
|
|
||
| // advance symbolindex forward until its address is >= the current addrToLine address | ||
| while (symbols[symbolIndex].address < addrToLine.address && symbolIndex < symbolIndexEnd) { | ||
| ++symbolIndex; | ||
| } | ||
|
|
||
| // create new symbol if we didn't match the address | ||
| if (symbols[symbolIndex].address > addrToLine.address) { | ||
| Symbols s; | ||
| s.address = addrToLine.address; | ||
| s.symbols.append(Symbol::createSourceLine(addrToLine.address, sourceLine)); | ||
| symbols.append(s); | ||
| } | ||
| else { | ||
| symbols[symbolIndex].symbols.append(Symbol::createSourceLine(addrToLine.address, sourceLine)); | ||
| } | ||
| } | ||
| } | ||
| emit updated(); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::revalidate() { | ||
| if (isValid) { | ||
| return; | ||
| } | ||
|
|
||
| // Don't know how to do this with pure nall stuff :( | ||
| int numSymbols = symbols.size(); | ||
| Symbols *temp = new Symbols[numSymbols]; | ||
| for (int i=0; i<numSymbols; i++) { | ||
| temp[i] = symbols[i]; | ||
| } | ||
|
|
||
| nall::sort(temp, numSymbols); | ||
|
|
||
| symbols.reset(); | ||
| symbols.reserve(numSymbols); | ||
| for (int i=0; i<numSymbols; i++) { | ||
| symbols.append(temp[i]); | ||
| } | ||
|
|
||
| isValid = true; | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| Symbol SymbolMap::getSymbol(uint32_t address) { | ||
| int32_t index = getSymbolIndex(address); | ||
| if (index == -1) { | ||
| return Symbol::createInvalid(); | ||
| } | ||
|
|
||
| return symbols[index].getSymbol(); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| Symbol SymbolMap::getComment(uint32_t address) { | ||
| int32_t index = getSymbolIndex(address); | ||
| if (index == -1) { | ||
| return Symbol::createInvalid(); | ||
| } | ||
|
|
||
| return symbols[index].getComment(); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| Symbol SymbolMap::getSourceLine(uint32_t address) { | ||
| int32_t index = getSymbolIndex(address); | ||
| if (index == -1) { | ||
| return Symbol::createInvalid(); | ||
| } | ||
|
|
||
| return symbols[index].getSourceLine(); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::removeSymbol(uint32_t address, Symbol::Type type) { | ||
| int32_t index = getSymbolIndex(address); | ||
| if (index == -1) { | ||
| return; | ||
| } | ||
|
|
||
| Symbols &s = symbols[index]; | ||
| for (int32_t i=0; i<s.symbols.size(); i++) { | ||
| if (s.symbols[i].type == type) { | ||
| s.symbols.remove(i); | ||
| i--; | ||
| } | ||
| } | ||
|
|
||
| if (s.symbols.size() == 0) { | ||
| symbols.remove(index); | ||
| isValid = false; | ||
| } | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::loadFromFile(const string &baseName, const string &ext) { | ||
| string fileName = baseName; | ||
| fileName.append(ext); | ||
|
|
||
| ::nall::file f; | ||
| if (!f.open((const char*)fileName, ::nall::file::mode::read)) { | ||
| return; | ||
| } | ||
|
|
||
| int size = f.size(); | ||
| char *buffer = new char[size + 1]; | ||
| buffer[size] = 0; | ||
| f.read((uint8_t*)buffer, f.size()); | ||
| loadFromString(buffer); | ||
|
|
||
| delete[] buffer; | ||
|
|
||
| f.close(); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolMap::loadFromString(const string &file) { | ||
| nall::lstring rows; | ||
| rows.split("\n", file); | ||
|
|
||
| SymbolFileInterface *adapter = adapters->findBestAdapter(rows); | ||
| if (adapter == NULL) { | ||
| return; | ||
| } | ||
|
|
||
| if (adapter->read(rows, this)) { | ||
| finishUpdates(); | ||
| } | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ |
| @@ -0,0 +1,133 @@ | ||
| #ifndef __SYMBOL_MAP__H__ | ||
| #define __SYMBOL_MAP__H__ | ||
|
|
||
| class SymbolFileAdapters; | ||
|
|
||
| struct Symbol { | ||
| enum Type { INVALID, LOCATION, COMMENT, SOURCE_LINE }; | ||
|
|
||
| static Symbol createInvalid() { | ||
| Symbol s; | ||
| s.type = INVALID; | ||
| return s; | ||
| } | ||
|
|
||
| static Symbol createComment(uint32_t address, const string &name) { | ||
| Symbol s; | ||
| s.type = COMMENT; | ||
| s.address = address; | ||
| s.name = name; | ||
| return s; | ||
| } | ||
|
|
||
| static Symbol createLocation(uint32_t address, const string &name) { | ||
| Symbol s; | ||
| s.type = LOCATION; | ||
| s.address = address; | ||
| s.name = name; | ||
| return s; | ||
| } | ||
|
|
||
| static Symbol createSourceLine(uint32_t address, const string &name) { | ||
| Symbol s; | ||
| s.type = SOURCE_LINE; | ||
| s.address = address; | ||
| s.name = name; | ||
| return s; | ||
| } | ||
|
|
||
| inline bool isInvalid() const { | ||
| return type == INVALID; | ||
| } | ||
|
|
||
| inline bool isSymbol() const { | ||
| return type == LOCATION; | ||
| } | ||
|
|
||
| inline bool isComment() const { | ||
| return type == COMMENT; | ||
| } | ||
|
|
||
| inline bool isSourceLine() const { | ||
| return type == SOURCE_LINE; | ||
| } | ||
|
|
||
| bool operator <(const Symbol &other) { | ||
| return address < other.address; | ||
| } | ||
|
|
||
| uint32_t address; | ||
| string name; | ||
| Type type; | ||
| }; | ||
|
|
||
| struct Symbols { | ||
| typedef nall::linear_vector<Symbol> SymbolList; | ||
|
|
||
| uint32_t address; | ||
| SymbolList symbols; | ||
|
|
||
| Symbol getSymbol(); | ||
| Symbol getComment(); | ||
| Symbol getSourceLine(); | ||
|
|
||
| bool operator <(const Symbols &other) { | ||
| return address < other.address; | ||
| } | ||
| }; | ||
|
|
||
| class SymbolMap : public QObject { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| SymbolMap(); | ||
|
|
||
| typedef nall::linear_vector<Symbols> SymbolsLists; | ||
|
|
||
| void addLocation(uint32_t address, const string &name); | ||
| void addComment(uint32_t address, const string &name); | ||
| void addSymbol(uint32_t address, const Symbol &name); | ||
| void addCommand(uint32_t id, const string &content); | ||
| void addSourceLine(uint32_t address, uint32_t file, uint32_t line); | ||
| void addSourceFile(uint32_t fileId, uint32_t checksum, const string &filename); | ||
| void removeSymbol(uint32_t address, Symbol::Type type); | ||
| void loadFromString(const string &file); | ||
| void loadFromFile(const string &baseName, const string &ext); | ||
| void saveToFile(const string &baseName, const string &ext); | ||
| void finishUpdates(); | ||
|
|
||
| void revalidate(); | ||
|
|
||
| int32_t getSymbolIndex(uint32_t address); | ||
| Symbol getSymbol(uint32_t address); | ||
| Symbol getComment(uint32_t address); | ||
| Symbol getSourceLine(uint32_t address); | ||
|
|
||
| bool isValid; | ||
| SymbolsLists symbols; | ||
| SymbolFileAdapters *adapters; | ||
|
|
||
| private: | ||
|
|
||
| struct AddressToSourceLine { | ||
| uint32_t address; | ||
| uint32_t file; | ||
| uint32_t line; | ||
|
|
||
| bool operator <(const AddressToSourceLine &other) { return address < other.address; } | ||
| }; | ||
| nall::linear_vector<AddressToSourceLine> addressToSourceLineMappings; | ||
|
|
||
| struct SourceFileInformation { | ||
| string filename; | ||
| unsigned long checksum; | ||
| }; | ||
| linear_vector<SourceFileInformation> sourceFiles; | ||
| linear_vector<lstring> sourceFileLines; | ||
|
|
||
| signals: | ||
| void updated(); | ||
|
|
||
| }; | ||
|
|
||
| #endif |
| @@ -0,0 +1,202 @@ | ||
| const char *DEFAULT_SYMBOL_MAP_CPU = | ||
| "; default registers used for CPU\n" \ | ||
| "\n" \ | ||
| "[labels]; simple labels\n" \ | ||
| "00:2100 SNES.INIDISP\n" \ | ||
| "00:2101 SNES.OBSEL\n" \ | ||
| "00:2102 SNES.OAMADDL\n" \ | ||
| "00:2103 SNES.OAMADDH\n" \ | ||
| "00:2104 SNES.OAMDATA\n" \ | ||
| "00:2105 SNES.BGMODE\n" \ | ||
| "00:2106 SNES.MOSAIC\n" \ | ||
| "00:2107 SNES.BG1SC\n" \ | ||
| "00:2108 SNES.BG2SC\n" \ | ||
| "00:2109 SNES.BG3SC\n" \ | ||
| "00:210A SNES.BG3SC\n" \ | ||
| "00:210B SNES.BG12NBA\n" \ | ||
| "00:210C SNES.BG34NBA\n" \ | ||
| "00:210D SNES.BG1HOFS\n" \ | ||
| "00:210E SNES.BG1VOFS\n" \ | ||
| "00:210F SNES.BG2HOFS\n" \ | ||
| "00:2110 SNES.BG2VOFS\n" \ | ||
| "00:2111 SNES.BG3HOFS\n" \ | ||
| "00:2112 SNES.BG3VOFS\n" \ | ||
| "00:2113 SNES.BG4HOFS\n" \ | ||
| "00:2114 SNES.BG4VOFS\n" \ | ||
| "00:2115 SNES.VMAIN\n" \ | ||
| "00:2116 SNES.VMADDL\n" \ | ||
| "00:2117 SNES.VMADDH\n" \ | ||
| "00:2118 SNES.VMDATAL\n" \ | ||
| "00:2119 SNES.VMDATAH\n" \ | ||
| "00:211A SNES.M7SEL\n" \ | ||
| "00:211B SNES.M7A\n" \ | ||
| "00:211C SNES.M7B\n" \ | ||
| "00:211D SNES.M7C\n" \ | ||
| "00:211E SNES.M7D\n" \ | ||
| "00:211F SNES.M7X\n" \ | ||
| "00:2120 SNES.M7Y\n" \ | ||
| "00:2121 SNES.CGADD\n" \ | ||
| "00:2122 SNES.CGDATA\n" \ | ||
| "00:2123 SNES.W12SEL\n" \ | ||
| "00:2124 SNES.W34SEL\n" \ | ||
| "00:2125 SNES.WOBJSEL\n" \ | ||
| "00:2126 SNES.WH0\n" \ | ||
| "00:2127 SNES.WH1\n" \ | ||
| "00:2128 SNES.WH2\n" \ | ||
| "00:2129 SNES.WH3\n" \ | ||
| "00:212A SNES.WBGLOG\n" \ | ||
| "00:212B SNES.WOBJLOG\n" \ | ||
| "00:212C SNES.TM\n" \ | ||
| "00:212D SNES.TS\n" \ | ||
| "00:212E SNES.TMW\n" \ | ||
| "00:212F SNES.TSW\n" \ | ||
| "00:2130 SNES.CGWSEL\n" \ | ||
| "00:2131 SNES.CGADSUB\n" \ | ||
| "00:2132 SNES.COLDATA\n" \ | ||
| "00:2133 SNES.SETINI\n" \ | ||
| "00:2134 SNES.MPYL\n" \ | ||
| "00:2135 SNES.MPYM\n" \ | ||
| "00:2136 SNES.MPYH\n" \ | ||
| "00:2137 SNES.SLHV\n" \ | ||
| "00:2138 SNES.OAMDATAREAD\n" \ | ||
| "00:2139 SNES.VMDATALREAD\n" \ | ||
| "00:213A SNES.VMDATAHREAD\n" \ | ||
| "00:213B SNES.CGDATAREAD\n" \ | ||
| "00:213C SNES.OPHCT\n" \ | ||
| "00:213D SNES.OPVCT\n" \ | ||
| "00:213E SNES.STAT77\n" \ | ||
| "00:213F SNES.STAT78\n" \ | ||
| "00:2140 SNES.APUIO0\n" \ | ||
| "00:2141 SNES.APUIO1\n" \ | ||
| "00:2142 SNES.APUIO2\n" \ | ||
| "00:2143 SNES.APUIO3\n" \ | ||
| "00:2180 SNES.WMDATA\n" \ | ||
| "00:2181 SNES.WMADDL\n" \ | ||
| "00:2182 SNES.WMADDM\n" \ | ||
| "00:2183 SNES.WMADDH\n" \ | ||
| "00:4016 SNES.JOYSER0\n" \ | ||
| "00:4017 SNES.JOYSER1\n" \ | ||
| "00:4200 SNES.NMITIMEN\n" \ | ||
| "00:4201 SNES.WRIO\n" \ | ||
| "00:4202 SNES.WRMPYA\n" \ | ||
| "00:4203 SNES.WRMPYB\n" \ | ||
| "00:4204 SNES.WRDIVL\n" \ | ||
| "00:4205 SNES.WRDIVH\n" \ | ||
| "00:4206 SNES.WRDIVB\n" \ | ||
| "00:4207 SNES.HTIMEL\n" \ | ||
| "00:4208 SNES.HTIMEH\n" \ | ||
| "00:4209 SNES.VTIMEL\n" \ | ||
| "00:420A SNES.VTIMEH\n" \ | ||
| "00:420B SNES.MDMAEN\n" \ | ||
| "00:420C SNES.HDMAEN\n" \ | ||
| "00:420D SNES.MEMSEL\n" \ | ||
| "00:4210 SNES.RDNMI\n" \ | ||
| "00:4211 SNES.TIMEUP\n" \ | ||
| "00:4212 SNES.HVBJOY\n" \ | ||
| "00:4213 SNES.RDIO\n" \ | ||
| "00:4214 SNES.RDDIVL\n" \ | ||
| "00:4215 SNES.RDDIVH\n" \ | ||
| "00:4216 SNES.RDMPYL\n" \ | ||
| "00:4217 SNES.RDMPYH\n" \ | ||
| "00:4218 SNES.JOY1L\n" \ | ||
| "00:4219 SNES.JOY1H\n" \ | ||
| "00:421A SNES.JOY2L\n" \ | ||
| "00:421B SNES.JOY2H\n" \ | ||
| "00:421C SNES.JOY3L\n" \ | ||
| "00:421D SNES.JOY3H\n" \ | ||
| "00:421E SNES.JOY4L\n" \ | ||
| "00:421F SNES.JOY4H\n" \ | ||
| "00:4300 SNES.DMAP0\n" \ | ||
| "00:4301 SNES.BBAD0\n" \ | ||
| "00:4302 SNES.A1T0L\n" \ | ||
| "00:4303 SNES.A1T0H\n" \ | ||
| "00:4304 SNES.A1B0\n" \ | ||
| "00:4305 SNES.DAS0L\n" \ | ||
| "00:4306 SNES.DAS0H\n" \ | ||
| "00:4307 SNES.DASB0\n" \ | ||
| "00:4308 SNES.A2A0L\n" \ | ||
| "00:4309 SNES.A2A0H\n" \ | ||
| "00:430A SNES.NTLR0\n" \ | ||
| "00:4310 SNES.DMAP1\n" \ | ||
| "00:4311 SNES.BBAD1\n" \ | ||
| "00:4312 SNES.A1T1L\n" \ | ||
| "00:4313 SNES.A1T1H\n" \ | ||
| "00:4314 SNES.A1B1\n" \ | ||
| "00:4315 SNES.DAS1L\n" \ | ||
| "00:4316 SNES.DAS1H\n" \ | ||
| "00:4317 SNES.DASB1\n" \ | ||
| "00:4318 SNES.A2A1L\n" \ | ||
| "00:4319 SNES.A2A1H\n" \ | ||
| "00:431A SNES.NTLR1\n" \ | ||
| "00:4320 SNES.DMAP2\n" \ | ||
| "00:4321 SNES.BBAD2\n" \ | ||
| "00:4322 SNES.A1T2L\n" \ | ||
| "00:4323 SNES.A1T2H\n" \ | ||
| "00:4324 SNES.A1B2\n" \ | ||
| "00:4325 SNES.DAS2L\n" \ | ||
| "00:4326 SNES.DAS2H\n" \ | ||
| "00:4327 SNES.DASB2\n" \ | ||
| "00:4328 SNES.A2A2L\n" \ | ||
| "00:4329 SNES.A2A2H\n" \ | ||
| "00:432A SNES.NTLR2\n" \ | ||
| "00:4330 SNES.DMAP3\n" \ | ||
| "00:4331 SNES.BBAD3\n" \ | ||
| "00:4332 SNES.A1T3L\n" \ | ||
| "00:4333 SNES.A1T3H\n" \ | ||
| "00:4334 SNES.A1B3\n" \ | ||
| "00:4335 SNES.DAS3L\n" \ | ||
| "00:4336 SNES.DAS3H\n" \ | ||
| "00:4337 SNES.DASB3\n" \ | ||
| "00:4338 SNES.A2A3L\n" \ | ||
| "00:4339 SNES.A2A3H\n" \ | ||
| "00:433A SNES.NTLR3\n" \ | ||
| "00:4340 SNES.DMAP4\n" \ | ||
| "00:4341 SNES.BBAD4\n" \ | ||
| "00:4342 SNES.A1T4L\n" \ | ||
| "00:4343 SNES.A1T4H\n" \ | ||
| "00:4344 SNES.A1B4\n" \ | ||
| "00:4345 SNES.DAS4L\n" \ | ||
| "00:4346 SNES.DAS4H\n" \ | ||
| "00:4347 SNES.DASB4\n" \ | ||
| "00:4348 SNES.A2A4L\n" \ | ||
| "00:4349 SNES.A2A4H\n" \ | ||
| "00:434A SNES.NTLR4\n" \ | ||
| "00:4350 SNES.DMAP5\n" \ | ||
| "00:4351 SNES.BBAD5\n" \ | ||
| "00:4352 SNES.A1T5L\n" \ | ||
| "00:4353 SNES.A1T5H\n" \ | ||
| "00:4354 SNES.A1B5\n" \ | ||
| "00:4355 SNES.DAS5L\n" \ | ||
| "00:4356 SNES.DAS5H\n" \ | ||
| "00:4357 SNES.DASB5\n" \ | ||
| "00:4358 SNES.A2A5L\n" \ | ||
| "00:4359 SNES.A2A5H\n" \ | ||
| "00:435A SNES.NTLR5\n" \ | ||
| "00:4360 SNES.DMAP6\n" \ | ||
| "00:4361 SNES.BBAD6\n" \ | ||
| "00:4362 SNES.A1T6L\n" \ | ||
| "00:4363 SNES.A1T6H\n" \ | ||
| "00:4364 SNES.A1B6\n" \ | ||
| "00:4365 SNES.DAS6L\n" \ | ||
| "00:4366 SNES.DAS6H\n" \ | ||
| "00:4367 SNES.DASB6\n" \ | ||
| "00:4368 SNES.A2A6L\n" \ | ||
| "00:4369 SNES.A2A6H\n" \ | ||
| "00:436A SNES.NTLR6\n" \ | ||
| "00:4370 SNES.DMAP7\n" \ | ||
| "00:4371 SNES.BBAD7\n" \ | ||
| "00:4372 SNES.A1T7L\n" \ | ||
| "00:4373 SNES.A1T7H\n" \ | ||
| "00:4374 SNES.A1B7\n" \ | ||
| "00:4375 SNES.DAS7L\n" \ | ||
| "00:4376 SNES.DAS7H\n" \ | ||
| "00:4377 SNES.DASB7\n" \ | ||
| "00:4378 SNES.A2A7L\n" \ | ||
| "00:4379 SNES.A2A7H\n" \ | ||
| "00:437A SNES.NTLR7\n" \ | ||
| "\n" \ | ||
| "[definitions]\n" \ | ||
| "00000000 test\n" \ | ||
| "00000000 test\n" \ | ||
| "00000000 test\n" \ | ||
| ; |
| @@ -0,0 +1,19 @@ | ||
| const char *DEFAULT_SYMBOL_MAP_SMP = | ||
| "; default registers used for SMP\n" \ | ||
| "\n" \ | ||
| "[labels]\n" \ | ||
| "00:00F0 SMP.UNKNOWN\n" \ | ||
| "00:00F1 SMP.CONTROL\n" \ | ||
| "00:00F2 SMP.DSP_ADDR\n" \ | ||
| "00:00F3 SMP.DSP_DATA\n" \ | ||
| "00:00F4 SMP.PORT0\n" \ | ||
| "00:00F5 SMP.PORT1\n" \ | ||
| "00:00F6 SMP.PORT2\n" \ | ||
| "00:00F7 SMP.PORT3\n" \ | ||
| "00:00FA SMP.TIMER0\n" \ | ||
| "00:00FB SMP.TIMER1\n" \ | ||
| "00:00FC SMP.TIMER2\n" \ | ||
| "00:00FD SMP.COUNTER0\n" \ | ||
| "00:00FE SMP.COUNTER1\n" \ | ||
| "00:00FF SMP.COUNTER2\n" \ | ||
| ; |
| @@ -0,0 +1,103 @@ | ||
| #include "symbolsview.moc" | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| SymbolsView::SymbolsView(DisasmProcessor *processor) : processor(processor) { | ||
| setObjectName("symbols"); | ||
| setWindowTitle("Symbols"); | ||
| application.windowList.append(this); | ||
|
|
||
| layout = new QVBoxLayout; | ||
| layout->setMargin(Style::WindowMargin); | ||
| layout->setSpacing(Style::WidgetSpacing); | ||
| setLayout(layout); | ||
|
|
||
| QHBoxLayout *topLayout = new QHBoxLayout(); | ||
| layout->addLayout(topLayout); | ||
|
|
||
| search = new QLineEdit(); | ||
| topLayout->addWidget(search); | ||
|
|
||
| list = new QTreeWidget; | ||
| list->setColumnCount(3); | ||
| list->setHeaderLabels(QStringList() << "Address" << "Name" << "Description"); | ||
| list->setColumnWidth(1, list->fontMetrics().width(" 123456789 ")); | ||
| list->setAllColumnsShowFocus(true); | ||
| list->sortByColumn(0, Qt::AscendingOrder); | ||
| list->setRootIsDecorated(false); | ||
| list->setSelectionMode(QAbstractItemView::ExtendedSelection); | ||
| list->resizeColumnToContents(0); | ||
| layout->addWidget(list); | ||
|
|
||
| resize(400, 500); | ||
| synchronize(); | ||
|
|
||
| connect(processor->getSymbols(), SIGNAL(updated()), this, SLOT(synchronize())); | ||
| connect(list, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(bind(QTreeWidgetItem*, int))); | ||
| connect(search, SIGNAL(textChanged(const QString&)), this, SLOT(synchronize())); | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolsView::bind(QTreeWidgetItem *item, int value) { | ||
| if (value != 0) { | ||
| return; | ||
| } | ||
|
|
||
| uint32_t address = item->data(0, Qt::UserRole).toUInt(); | ||
| bool enable = item->checkState(0); | ||
|
|
||
| int32_t breakpoint = breakpointEditor->indexOfBreakpointExec(address, processor->getBreakpointBusName()); | ||
| if (!enable && breakpoint >= 0) { | ||
| breakpointEditor->removeBreakpoint(breakpoint); | ||
| } else if (enable) { | ||
| breakpointEditor->addBreakpoint(nall::hex(address), "x", processor->getBreakpointBusName()); | ||
| } | ||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ | ||
| void SymbolsView::synchronize() { | ||
| QString filter = search->text(); | ||
| SymbolMap *symbols = processor->getSymbols(); | ||
|
|
||
| list->clear(); | ||
| list->setSortingEnabled(false); | ||
|
|
||
| uint32_t count = symbols->symbols.size(); | ||
| for (uint32_t i=0; i<count; i++) { | ||
| const Symbol &sym = symbols->symbols[i].getSymbol(); | ||
| if (sym.isInvalid()) { | ||
| continue; | ||
| } | ||
|
|
||
| if (filter.length()) { | ||
| QStringList list = filter.split(" "); | ||
| QString search = QString((const char*)sym.name); | ||
| bool found = true; | ||
|
|
||
| for (QStringList::iterator it = list.begin(); it != list.end() && found; it++) { | ||
| if (!search.contains(*it, Qt::CaseInsensitive)) { | ||
| found = false; | ||
| } | ||
| } | ||
|
|
||
| if (!found) { | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| int32_t breakpoint = breakpointEditor->indexOfBreakpointExec(sym.address, processor->getBreakpointBusName()); | ||
|
|
||
| auto item = new QTreeWidgetItem(list); | ||
| item->setData(0, Qt::UserRole, QVariant(sym.address)); | ||
| item->setCheckState(0, breakpoint >= 0 ? Qt::Checked : Qt::Unchecked); | ||
| item->setText(0, hex<6, '0'>(sym.address)); | ||
| item->setText(1, sym.name); | ||
| item->setText(2, ""); | ||
| } | ||
|
|
||
| list->resizeColumnToContents(0); | ||
| list->resizeColumnToContents(1); | ||
| list->setSortingEnabled(true); | ||
|
|
||
| } | ||
|
|
||
| // ------------------------------------------------------------------------ |
| @@ -0,0 +1,20 @@ | ||
| class Symbols; | ||
|
|
||
| class SymbolsView : public Window { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| SymbolsView(class DisasmProcessor *processor); | ||
|
|
||
| QVBoxLayout *layout; | ||
| QTreeWidget *list; | ||
|
|
||
| QLineEdit *search; | ||
|
|
||
| public slots: | ||
| void synchronize(); | ||
| void bind(QTreeWidgetItem*, int); | ||
|
|
||
| private: | ||
| class DisasmProcessor *processor; | ||
| }; |