diff --git a/src/asm.cpp b/src/asm.cpp index 1c57d93b..533bb0b1 100644 --- a/src/asm.cpp +++ b/src/asm.cpp @@ -3,6 +3,7 @@ #include "types.h" #include "utils/xstring.h" +#include "utils/StringBuilder.h" #include "debug.h" #include "asm.h" #include "x6502.h" @@ -256,8 +257,11 @@ int Assemble(unsigned char *output, int addr, char *str) { ///disassembles the opcodes in the buffer assuming the provided address. Uses GetMem() and 6502 current registers to query referenced values. returns a static string buffer. char *Disassemble(int addr, uint8 *opcode) { - static char str[64]={0},chr[5]={0}; + static char str[64]={0}; + const char *chr; + char indReg; uint16 tmp,tmp2; + StringBuilder sb(str); //these may be replaced later with passed-in values to make a lighter-weight disassembly mode that may not query the referenced values #define RX (X.X) @@ -286,7 +290,7 @@ char *Disassemble(int addr, uint8 *opcode) { #ifdef BRK_3BYTE_HACK case 0x00: - snprintf(str, sizeof(str), "BRK %02X %02X", opcode[1], opcode[2]); + sb << "BRK " << sb_hex(opcode[1], 2) << ' ' << sb_hex(opcode[2], 2); break; #else case 0x00: strcpy(str,"BRK"); break; @@ -323,207 +327,228 @@ char *Disassemble(int addr, uint8 *opcode) { case 0xF8: strcpy(str,"SED"); break; //(Indirect,X) - case 0x01: strcpy(chr,"ORA"); goto _indirectx; - case 0x21: strcpy(chr,"AND"); goto _indirectx; - case 0x41: strcpy(chr,"EOR"); goto _indirectx; - case 0x61: strcpy(chr,"ADC"); goto _indirectx; - case 0x81: strcpy(chr,"STA"); goto _indirectx; - case 0xA1: strcpy(chr,"LDA"); goto _indirectx; - case 0xC1: strcpy(chr,"CMP"); goto _indirectx; - case 0xE1: strcpy(chr,"SBC"); goto _indirectx; + case 0x01: chr = "ORA"; goto _indirectx; + case 0x21: chr = "AND"; goto _indirectx; + case 0x41: chr = "EOR"; goto _indirectx; + case 0x61: chr = "ADC"; goto _indirectx; + case 0x81: chr = "STA"; goto _indirectx; + case 0xA1: chr = "LDA"; goto _indirectx; + case 0xC1: chr = "CMP"; goto _indirectx; + case 0xE1: chr = "SBC"; goto _indirectx; _indirectx: indirectX(tmp); - snprintf(str, sizeof(str), "%s ($%02X,X) @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); + indReg = 'X'; + + _indirect: + sb << chr << " (" << sb_addr(opcode[1], 2) << ',' << indReg << ") @ " << sb_addr(tmp) << " = " << sb_lit(GetMem(tmp)); break; //Zero Page - case 0x05: strcpy(chr,"ORA"); goto _zeropage; - case 0x06: strcpy(chr,"ASL"); goto _zeropage; - case 0x24: strcpy(chr,"BIT"); goto _zeropage; - case 0x25: strcpy(chr,"AND"); goto _zeropage; - case 0x26: strcpy(chr,"ROL"); goto _zeropage; - case 0x45: strcpy(chr,"EOR"); goto _zeropage; - case 0x46: strcpy(chr,"LSR"); goto _zeropage; - case 0x65: strcpy(chr,"ADC"); goto _zeropage; - case 0x66: strcpy(chr,"ROR"); goto _zeropage; - case 0x84: strcpy(chr,"STY"); goto _zeropage; - case 0x85: strcpy(chr,"STA"); goto _zeropage; - case 0x86: strcpy(chr,"STX"); goto _zeropage; - case 0xA4: strcpy(chr,"LDY"); goto _zeropage; - case 0xA5: strcpy(chr,"LDA"); goto _zeropage; - case 0xA6: strcpy(chr,"LDX"); goto _zeropage; - case 0xC4: strcpy(chr,"CPY"); goto _zeropage; - case 0xC5: strcpy(chr,"CMP"); goto _zeropage; - case 0xC6: strcpy(chr,"DEC"); goto _zeropage; - case 0xE4: strcpy(chr,"CPX"); goto _zeropage; - case 0xE5: strcpy(chr,"SBC"); goto _zeropage; - case 0xE6: strcpy(chr,"INC"); goto _zeropage; + case 0x05: chr = "ORA"; goto _zeropage; + case 0x06: chr = "ASL"; goto _zeropage; + case 0x24: chr = "BIT"; goto _zeropage; + case 0x25: chr = "AND"; goto _zeropage; + case 0x26: chr = "ROL"; goto _zeropage; + case 0x45: chr = "EOR"; goto _zeropage; + case 0x46: chr = "LSR"; goto _zeropage; + case 0x65: chr = "ADC"; goto _zeropage; + case 0x66: chr = "ROR"; goto _zeropage; + case 0x84: chr = "STY"; goto _zeropage; + case 0x85: chr = "STA"; goto _zeropage; + case 0x86: chr = "STX"; goto _zeropage; + case 0xA4: chr = "LDY"; goto _zeropage; + case 0xA5: chr = "LDA"; goto _zeropage; + case 0xA6: chr = "LDX"; goto _zeropage; + case 0xC4: chr = "CPY"; goto _zeropage; + case 0xC5: chr = "CMP"; goto _zeropage; + case 0xC6: chr = "DEC"; goto _zeropage; + case 0xE4: chr = "CPX"; goto _zeropage; + case 0xE5: chr = "SBC"; goto _zeropage; + case 0xE6: chr = "INC"; goto _zeropage; _zeropage: // ################################## Start of SP CODE ########################### // Change width to %04X // don't! - snprintf(str, sizeof(str), "%s $%02X = #$%02X", chr,opcode[1],GetMem(opcode[1])); + sb << chr << ' ' << sb_addr(opcode[1], 2) << " = " << sb_lit(GetMem(opcode[1])); // ################################## End of SP CODE ########################### break; //#Immediate - case 0x09: strcpy(chr,"ORA"); goto _immediate; - case 0x29: strcpy(chr,"AND"); goto _immediate; - case 0x49: strcpy(chr,"EOR"); goto _immediate; - case 0x69: strcpy(chr,"ADC"); goto _immediate; - //case 0x89: strcpy(chr,"STA"); goto _immediate; //baka, no STA #imm!! - case 0xA0: strcpy(chr,"LDY"); goto _immediate; - case 0xA2: strcpy(chr,"LDX"); goto _immediate; - case 0xA9: strcpy(chr,"LDA"); goto _immediate; - case 0xC0: strcpy(chr,"CPY"); goto _immediate; - case 0xC9: strcpy(chr,"CMP"); goto _immediate; - case 0xE0: strcpy(chr,"CPX"); goto _immediate; - case 0xE9: strcpy(chr,"SBC"); goto _immediate; + case 0x09: chr = "ORA"; goto _immediate; + case 0x29: chr = "AND"; goto _immediate; + case 0x49: chr = "EOR"; goto _immediate; + case 0x69: chr = "ADC"; goto _immediate; + //case 0x89: chr = "STA"; goto _immediate; //baka, no STA #imm!! + case 0xA0: chr = "LDY"; goto _immediate; + case 0xA2: chr = "LDX"; goto _immediate; + case 0xA9: chr = "LDA"; goto _immediate; + case 0xC0: chr = "CPY"; goto _immediate; + case 0xC9: chr = "CMP"; goto _immediate; + case 0xE0: chr = "CPX"; goto _immediate; + case 0xE9: chr = "SBC"; goto _immediate; _immediate: - snprintf(str, sizeof(str), "%s #$%02X", chr,opcode[1]); + sb << chr << ' ' << sb_lit(opcode[1]); break; //Absolute - case 0x0D: strcpy(chr,"ORA"); goto _absolute; - case 0x0E: strcpy(chr,"ASL"); goto _absolute; - case 0x2C: strcpy(chr,"BIT"); goto _absolute; - case 0x2D: strcpy(chr,"AND"); goto _absolute; - case 0x2E: strcpy(chr,"ROL"); goto _absolute; - case 0x4D: strcpy(chr,"EOR"); goto _absolute; - case 0x4E: strcpy(chr,"LSR"); goto _absolute; - case 0x6D: strcpy(chr,"ADC"); goto _absolute; - case 0x6E: strcpy(chr,"ROR"); goto _absolute; - case 0x8C: strcpy(chr,"STY"); goto _absolute; - case 0x8D: strcpy(chr,"STA"); goto _absolute; - case 0x8E: strcpy(chr,"STX"); goto _absolute; - case 0xAC: strcpy(chr,"LDY"); goto _absolute; - case 0xAD: strcpy(chr,"LDA"); goto _absolute; - case 0xAE: strcpy(chr,"LDX"); goto _absolute; - case 0xCC: strcpy(chr,"CPY"); goto _absolute; - case 0xCD: strcpy(chr,"CMP"); goto _absolute; - case 0xCE: strcpy(chr,"DEC"); goto _absolute; - case 0xEC: strcpy(chr,"CPX"); goto _absolute; - case 0xED: strcpy(chr,"SBC"); goto _absolute; - case 0xEE: strcpy(chr,"INC"); goto _absolute; + case 0x0D: chr = "ORA"; goto _absolute; + case 0x0E: chr = "ASL"; goto _absolute; + case 0x2C: chr = "BIT"; goto _absolute; + case 0x2D: chr = "AND"; goto _absolute; + case 0x2E: chr = "ROL"; goto _absolute; + case 0x4D: chr = "EOR"; goto _absolute; + case 0x4E: chr = "LSR"; goto _absolute; + case 0x6D: chr = "ADC"; goto _absolute; + case 0x6E: chr = "ROR"; goto _absolute; + case 0x8C: chr = "STY"; goto _absolute; + case 0x8D: chr = "STA"; goto _absolute; + case 0x8E: chr = "STX"; goto _absolute; + case 0xAC: chr = "LDY"; goto _absolute; + case 0xAD: chr = "LDA"; goto _absolute; + case 0xAE: chr = "LDX"; goto _absolute; + case 0xCC: chr = "CPY"; goto _absolute; + case 0xCD: chr = "CMP"; goto _absolute; + case 0xCE: chr = "DEC"; goto _absolute; + case 0xEC: chr = "CPX"; goto _absolute; + case 0xED: chr = "SBC"; goto _absolute; + case 0xEE: chr = "INC"; goto _absolute; _absolute: absolute(tmp); - snprintf(str, sizeof(str), "%s $%04X = #$%02X", chr,tmp,GetMem(tmp)); + + sb << chr << ' ' << sb_addr(tmp) << " = " << sb_lit(GetMem(tmp)); + break; //branches - case 0x10: strcpy(chr,"BPL"); goto _branch; - case 0x30: strcpy(chr,"BMI"); goto _branch; - case 0x50: strcpy(chr,"BVC"); goto _branch; - case 0x70: strcpy(chr,"BVS"); goto _branch; - case 0x90: strcpy(chr,"BCC"); goto _branch; - case 0xB0: strcpy(chr,"BCS"); goto _branch; - case 0xD0: strcpy(chr,"BNE"); goto _branch; - case 0xF0: strcpy(chr,"BEQ"); goto _branch; + case 0x10: chr = "BPL"; goto _branch; + case 0x30: chr = "BMI"; goto _branch; + case 0x50: chr = "BVC"; goto _branch; + case 0x70: chr = "BVS"; goto _branch; + case 0x90: chr = "BCC"; goto _branch; + case 0xB0: chr = "BCS"; goto _branch; + case 0xD0: chr = "BNE"; goto _branch; + case 0xF0: chr = "BEQ"; goto _branch; _branch: relative(tmp); - snprintf(str, sizeof(str), "%s $%04X", chr,tmp); + + sb << chr << ' ' << sb_addr(tmp); + break; //(Indirect),Y - case 0x11: strcpy(chr,"ORA"); goto _indirecty; - case 0x31: strcpy(chr,"AND"); goto _indirecty; - case 0x51: strcpy(chr,"EOR"); goto _indirecty; - case 0x71: strcpy(chr,"ADC"); goto _indirecty; - case 0x91: strcpy(chr,"STA"); goto _indirecty; - case 0xB1: strcpy(chr,"LDA"); goto _indirecty; - case 0xD1: strcpy(chr,"CMP"); goto _indirecty; - case 0xF1: strcpy(chr,"SBC"); goto _indirecty; + case 0x11: chr = "ORA"; goto _indirecty; + case 0x31: chr = "AND"; goto _indirecty; + case 0x51: chr = "EOR"; goto _indirecty; + case 0x71: chr = "ADC"; goto _indirecty; + case 0x91: chr = "STA"; goto _indirecty; + case 0xB1: chr = "LDA"; goto _indirecty; + case 0xD1: chr = "CMP"; goto _indirecty; + case 0xF1: chr = "SBC"; goto _indirecty; _indirecty: indirectY(tmp); - snprintf(str, sizeof(str), "%s ($%02X),Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); - break; + indReg = 'Y'; + + goto _indirect; //Zero Page,X - case 0x15: strcpy(chr,"ORA"); goto _zeropagex; - case 0x16: strcpy(chr,"ASL"); goto _zeropagex; - case 0x35: strcpy(chr,"AND"); goto _zeropagex; - case 0x36: strcpy(chr,"ROL"); goto _zeropagex; - case 0x55: strcpy(chr,"EOR"); goto _zeropagex; - case 0x56: strcpy(chr,"LSR"); goto _zeropagex; - case 0x75: strcpy(chr,"ADC"); goto _zeropagex; - case 0x76: strcpy(chr,"ROR"); goto _zeropagex; - case 0x94: strcpy(chr,"STY"); goto _zeropagex; - case 0x95: strcpy(chr,"STA"); goto _zeropagex; - case 0xB4: strcpy(chr,"LDY"); goto _zeropagex; - case 0xB5: strcpy(chr,"LDA"); goto _zeropagex; - case 0xD5: strcpy(chr,"CMP"); goto _zeropagex; - case 0xD6: strcpy(chr,"DEC"); goto _zeropagex; - case 0xF5: strcpy(chr,"SBC"); goto _zeropagex; - case 0xF6: strcpy(chr,"INC"); goto _zeropagex; + case 0x15: chr = "ORA"; goto _zeropagex; + case 0x16: chr = "ASL"; goto _zeropagex; + case 0x35: chr = "AND"; goto _zeropagex; + case 0x36: chr = "ROL"; goto _zeropagex; + case 0x55: chr = "EOR"; goto _zeropagex; + case 0x56: chr = "LSR"; goto _zeropagex; + case 0x75: chr = "ADC"; goto _zeropagex; + case 0x76: chr = "ROR"; goto _zeropagex; + case 0x94: chr = "STY"; goto _zeropagex; + case 0x95: chr = "STA"; goto _zeropagex; + case 0xB4: chr = "LDY"; goto _zeropagex; + case 0xB5: chr = "LDA"; goto _zeropagex; + case 0xD5: chr = "CMP"; goto _zeropagex; + case 0xD6: chr = "DEC"; goto _zeropagex; + case 0xF5: chr = "SBC"; goto _zeropagex; + case 0xF6: chr = "INC"; goto _zeropagex; _zeropagex: - zpIndex(tmp,RX); + zpIndex(tmp, RX); + indReg = 'X'; + + _indexed: // ################################## Start of SP CODE ########################### // Change width to %04X // don't! - snprintf(str, sizeof(str), "%s $%02X,X @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); + sb << chr << ' ' << sb_addr(opcode[1], 2) << ',' << indReg << " @ " << sb_addr(tmp) << " = " << sb_lit(GetMem(tmp)); // ################################## End of SP CODE ########################### break; //Absolute,Y - case 0x19: strcpy(chr,"ORA"); goto _absolutey; - case 0x39: strcpy(chr,"AND"); goto _absolutey; - case 0x59: strcpy(chr,"EOR"); goto _absolutey; - case 0x79: strcpy(chr,"ADC"); goto _absolutey; - case 0x99: strcpy(chr,"STA"); goto _absolutey; - case 0xB9: strcpy(chr,"LDA"); goto _absolutey; - case 0xBE: strcpy(chr,"LDX"); goto _absolutey; - case 0xD9: strcpy(chr,"CMP"); goto _absolutey; - case 0xF9: strcpy(chr,"SBC"); goto _absolutey; + case 0x19: chr = "ORA"; goto _absolutey; + case 0x39: chr = "AND"; goto _absolutey; + case 0x59: chr = "EOR"; goto _absolutey; + case 0x79: chr = "ADC"; goto _absolutey; + case 0x99: chr = "STA"; goto _absolutey; + case 0xB9: chr = "LDA"; goto _absolutey; + case 0xBE: chr = "LDX"; goto _absolutey; + case 0xD9: chr = "CMP"; goto _absolutey; + case 0xF9: chr = "SBC"; goto _absolutey; _absolutey: absolute(tmp); - tmp2=(tmp+RY); - snprintf(str, sizeof(str), "%s $%04X,Y @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2)); + tmp2 = (tmp + RY); + indReg = 'Y'; + + _absindexed: + sb << chr << ' ' << sb_addr(tmp) << ',' << indReg << " @ " << sb_addr(tmp2) << " = " << sb_lit(GetMem(tmp2)); + break; //Absolute,X - case 0x1D: strcpy(chr,"ORA"); goto _absolutex; - case 0x1E: strcpy(chr,"ASL"); goto _absolutex; - case 0x3D: strcpy(chr,"AND"); goto _absolutex; - case 0x3E: strcpy(chr,"ROL"); goto _absolutex; - case 0x5D: strcpy(chr,"EOR"); goto _absolutex; - case 0x5E: strcpy(chr,"LSR"); goto _absolutex; - case 0x7D: strcpy(chr,"ADC"); goto _absolutex; - case 0x7E: strcpy(chr,"ROR"); goto _absolutex; - case 0x9D: strcpy(chr,"STA"); goto _absolutex; - case 0xBC: strcpy(chr,"LDY"); goto _absolutex; - case 0xBD: strcpy(chr,"LDA"); goto _absolutex; - case 0xDD: strcpy(chr,"CMP"); goto _absolutex; - case 0xDE: strcpy(chr,"DEC"); goto _absolutex; - case 0xFD: strcpy(chr,"SBC"); goto _absolutex; - case 0xFE: strcpy(chr,"INC"); goto _absolutex; + case 0x1D: chr = "ORA"; goto _absolutex; + case 0x1E: chr = "ASL"; goto _absolutex; + case 0x3D: chr = "AND"; goto _absolutex; + case 0x3E: chr = "ROL"; goto _absolutex; + case 0x5D: chr = "EOR"; goto _absolutex; + case 0x5E: chr = "LSR"; goto _absolutex; + case 0x7D: chr = "ADC"; goto _absolutex; + case 0x7E: chr = "ROR"; goto _absolutex; + case 0x9D: chr = "STA"; goto _absolutex; + case 0xBC: chr = "LDY"; goto _absolutex; + case 0xBD: chr = "LDA"; goto _absolutex; + case 0xDD: chr = "CMP"; goto _absolutex; + case 0xDE: chr = "DEC"; goto _absolutex; + case 0xFD: chr = "SBC"; goto _absolutex; + case 0xFE: chr = "INC"; goto _absolutex; _absolutex: absolute(tmp); - tmp2=(tmp+RX); - snprintf(str, sizeof(str), "%s $%04X,X @ $%04X = #$%02X", chr,tmp,tmp2,GetMem(tmp2)); - break; + tmp2 = (tmp + RX); + indReg = 'X'; + + goto _absindexed; //jumps - case 0x20: strcpy(chr,"JSR"); goto _jump; - case 0x4C: strcpy(chr,"JMP"); goto _jump; - case 0x6C: absolute(tmp); snprintf(str, sizeof(str), "JMP ($%04X) = $%04X", tmp,GetMem(tmp)|GetMem(tmp+1)<<8); break; + case 0x20: chr = "JSR"; goto _jump; + case 0x4C: chr = "JMP"; goto _jump; _jump: absolute(tmp); - snprintf(str, sizeof(str), "%s $%04X", chr,tmp); + + sb << chr << ' ' << sb_addr(tmp); + + break; + + case 0x6C: + absolute(tmp); + + sb << "JMP (" << sb_addr(tmp); + sb << ") = " << sb_addr(GetMem(tmp) | GetMem(tmp + 1) << 8); + break; //Zero Page,Y - case 0x96: strcpy(chr,"STX"); goto _zeropagey; - case 0xB6: strcpy(chr,"LDX"); goto _zeropagey; + case 0x96: chr = "STX"; goto _zeropagey; + case 0xB6: chr = "LDX"; goto _zeropagey; _zeropagey: - zpIndex(tmp,RY); - // ################################## Start of SP CODE ########################### - // Change width to %04X // don't! - snprintf(str, sizeof(str), "%s $%02X,Y @ $%04X = #$%02X", chr,opcode[1],tmp,GetMem(tmp)); - // ################################## End of SP CODE ########################### - break; + zpIndex(tmp, RY); + indReg = 'Y'; + + goto _indexed; //UNDEFINED - default: strcpy(str,"ERROR"); break; - + default: strcpy(str, "ERROR"); break; } - return str; } diff --git a/src/drivers/Qt/TraceLogger.cpp b/src/drivers/Qt/TraceLogger.cpp index 6eabb3c4..4e886413 100644 --- a/src/drivers/Qt/TraceLogger.cpp +++ b/src/drivers/Qt/TraceLogger.cpp @@ -25,7 +25,7 @@ #ifdef WIN32 #include -#include +#include "../win/TraceFileWriter.h" #else #include #include diff --git a/src/drivers/Qt/TraceFileWriter.h b/src/drivers/win/TraceFileWriter.h similarity index 97% rename from src/drivers/Qt/TraceFileWriter.h rename to src/drivers/win/TraceFileWriter.h index df249d6c..7877f715 100644 --- a/src/drivers/Qt/TraceFileWriter.h +++ b/src/drivers/win/TraceFileWriter.h @@ -125,7 +125,7 @@ public: // Add a line to the buffer and write it out when the buffer is filled // Under most failure cirumstances the line is added to the buffer - bool writeLine(const char *line) + bool writeLine(const char *line, bool addEol = true) { if (!isOpen) { @@ -138,6 +138,7 @@ public: size_t eolSize = strlen(eol); char *buff = buffers[buffIdx]; size_t lineLen = strlen(line); + size_t copyLen = lineLen + (addEol ? eolSize : 0); if (buffOffs + lineLen + eolSize > BuffSize) { // Buffer is full. This shouldn't ever happen. @@ -146,7 +147,8 @@ public: } memcpy(buff + buffOffs, line, lineLen); - memcpy(buff + buffOffs + lineLen, eol, eolSize); + if (addEol) + memcpy(buff + buffOffs + lineLen, eol, eolSize); buffOffs += lineLen + eolSize; // Check if the previous write is done, to detect it as early as possible @@ -202,7 +204,7 @@ public: } protected: - typedef BOOL (*SetFileInformationByHandlePtr)( + typedef BOOL (WINAPI *SetFileInformationByHandlePtr)( HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, diff --git a/src/drivers/win/debuggersp.cpp b/src/drivers/win/debuggersp.cpp index d40b5d06..eecfe493 100644 --- a/src/drivers/win/debuggersp.cpp +++ b/src/drivers/win/debuggersp.cpp @@ -27,10 +27,12 @@ #include "../../debug.h" #include "../../debugsymboltable.h" #include "../../conddebug.h" +#include "utils/StringBuilder.h" #include #include #include +#include int GetNesFileAddress(int A); @@ -62,7 +64,7 @@ bool symbRegNames = true; int debuggerWasActive = 0; char temp_chr[40] = {0}; char delimiterChar[2] = "#"; - + INT_PTR CALLBACK nameDebuggerBookmarkCallB(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); extern WNDPROC DefaultEditCtrlProc; @@ -103,8 +105,14 @@ MemoryMappedRegister RegNames[] = { {"$4017", "JOY2_FRAME"} }; +const char minRegFirstDigit = '2', maxRegFirstDigit = '4'; + int RegNameCount = sizeof(RegNames)/sizeof(MemoryMappedRegister); +auto cmpRegNames = [](const void *a, const void *b) { + return std::strncmp(((const MemoryMappedRegister *)a)->offset + 1, ((const MemoryMappedRegister *)b)->offset + 1, 4); +}; + /** * Parses a line from a NL file. * @param line The line to parse @@ -603,20 +611,39 @@ void replaceNames(Name* list, char* str, std::vector* addressesLog) list = list->next; } - for (int i = 0; i < RegNameCount; i++) { - if (!symbRegNames) break; - // copypaste, because Name* is too complex to abstract - *buff = 0; - src = str; + if (symbRegNames) { + StringBuilder sb(buff); - while (pos = strstr(src, RegNames[i].offset)) { - *pos = 0; - strcat(buff, src); - strcat(buff, RegNames[i].name); - src = pos + 5; + pos = src = str; + while (pos = std::strchr(pos, '$')) + { + char first = pos[1]; + if (first < minRegFirstDigit || first > maxRegFirstDigit) + { + pos += 1; + continue; + } + + MemoryMappedRegister key = { pos, "" }; + const MemoryMappedRegister *reg = (const MemoryMappedRegister *)std::bsearch(&key, RegNames, RegNameCount, sizeof(MemoryMappedRegister), cmpRegNames); + if (reg != nullptr) + { + *pos = '\0'; + sb << src << reg->name; + + pos += 5; + src = pos; + } + else + pos += 1; } - if (*buff) { - strcat(buff, src); + + // If no registers were found then the string is unmodified and no copies are necessary + if (src != str) + { + if (*src) + sb << src; + strcpy(str, buff); } } diff --git a/src/drivers/win/tracer.cpp b/src/drivers/win/tracer.cpp index 35f97eda..3ce622f1 100644 --- a/src/drivers/win/tracer.cpp +++ b/src/drivers/win/tracer.cpp @@ -32,8 +32,10 @@ #include "cdlogger.h" #include "tracer.h" #include "memview.h" +#include "TraceFileWriter.h" #include "main.h" //for GetRomName() #include "utils/xstring.h" +#include "utils/StringBuilder.h" //Used to determine the current hotkey mapping for the pause key in order to display on the dialog #include "mapinput.h" @@ -132,7 +134,7 @@ bool log_old_emu_paused = true; // thanks to this flag the window only updates extern bool JustFrameAdvanced; extern int currFrameCounter; -FILE *LOG_FP; +TraceFileWriter fileWriter; char trace_str[35000] = {0}; WNDPROC IDC_TRACER_LOG_oldWndProc = 0; @@ -686,14 +688,13 @@ void BeginLoggingSequence(void) { if(logfilename == NULL) ShowLogDirDialog(); if (!logfilename) return; - LOG_FP = fopen(logfilename,"w"); - if (LOG_FP == NULL) + if (!fileWriter.open(logfilename, false)) { sprintf(trace_str, "Error Opening File %s", logfilename); MessageBox(hTracer, trace_str, "File Error", MB_OK); return; } - fprintf(LOG_FP,FCEU_NAME_AND_VERSION" - Trace Log File\n"); //mbg merge 7/19/06 changed string + fileWriter.writeLine(FCEU_NAME_AND_VERSION" - Trace Log File"); } else { ClearTraceLogBuf(); @@ -734,8 +735,8 @@ void BeginLoggingSequence(void) void FCEUD_FlushTrace() { - if(LOG_FP) - fflush(LOG_FP); + if(fileWriter.getOpen()) + fileWriter.flush(); } //todo: really speed this up @@ -745,8 +746,8 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) return; unsigned int addr = X.PC; - uint8 tmp; static int unloggedlines; + StringBuilder dataSb(str_data), dasmSb(str_disassembly), resSb(str_result); // if instruction executed from the RAM, skip this, log all instead // TODO: loops folding mame-lyke style @@ -760,7 +761,7 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) olddatacount = datacount; if(unloggedlines > 0) { - sprintf(str_result, "(%d lines skipped)", unloggedlines); + resSb << '(' << sb_dec(unloggedlines) << " lines skipped)"; OutputLogLine(str_result); unloggedlines = 0; } @@ -778,20 +779,22 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) if ((addr + size) > 0xFFFF) { - sprintf(str_data, "%02X ", opcode[0]); - sprintf(str_disassembly, "OVERFLOW"); + dataSb << sb_hex(opcode[0], 2) << " "; + dasmSb << "OVERFLOW"; } else { char* a = 0; switch (size) { case 0: - sprintf(str_data, "%02X ", opcode[0]); - sprintf(str_disassembly,"UNDEFINED"); + dataSb << sb_hex(opcode[0], 2) << " "; + dasmSb << "UNDEFINED"; break; case 1: { - sprintf(str_data, "%02X ", opcode[0]); + StringBuilder decSb(str_decoration); + + dataSb << sb_hex(opcode[0], 2) << " "; a = Disassemble(addr + 1, opcode); // special case: an RTS opcode if (opcode[0] == 0x60) @@ -802,18 +805,18 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) { // this was a JSR instruction - take the subroutine address from it unsigned int call_addr = GetMem(caller_addr + 1) + (GetMem(caller_addr + 2) << 8); - sprintf(str_decoration, " (from $%04X)", call_addr); + decSb << " (from " << sb_addr(call_addr) << ')'; strcat(a, str_decoration); } } break; } case 2: - sprintf(str_data, "%02X %02X ", opcode[0],opcode[1]); + dataSb << sb_hex(opcode[0], 2) << ' ' << sb_hex(opcode[1], 2) << " "; a = Disassemble(addr + 2, opcode); break; case 3: - sprintf(str_data, "%02X %02X %02X ", opcode[0],opcode[1],opcode[2]); + dataSb << sb_hex(opcode[0], 2) << ' ' << sb_hex(opcode[1], 2) << ' ' << sb_hex(opcode[2], 2) << " "; a = Disassemble(addr + 3, opcode); break; } @@ -822,6 +825,8 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) { if (logging_options & LOG_SYMBOLIC) { + StringBuilder decSb(str_decoration); + loadNameFiles(); tempAddressesLog.resize(0); // Insert Name and Comment lines if needed @@ -830,24 +835,22 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) { if (node->name) { - strcpy(str_decoration, node->name); - strcat(str_decoration, ":"); + decSb << node->name << ':'; tempAddressesLog.push_back(addr); OutputLogLine(str_decoration, &tempAddressesLog); } if (node->comment) { // make a copy - strcpy(str_decoration_comment, node->comment); - strcat(str_decoration_comment, "\r\n"); + StringBuilder cmtSb(str_decoration_comment); + cmtSb << node->comment << "\r\n"; tracer_decoration_comment = str_decoration_comment; // divide the str_decoration_comment into strings (Comment1, Comment2, ...) char* tracer_decoration_comment_end_pos = strstr(tracer_decoration_comment, "\r\n"); while (tracer_decoration_comment_end_pos) { tracer_decoration_comment_end_pos[0] = 0; // set \0 instead of \r - strcpy(str_decoration, "; "); - strcat(str_decoration, tracer_decoration_comment); + decSb << "; " << tracer_decoration_comment; OutputLogLine(str_decoration, &tempAddressesLog); tracer_decoration_comment_end_pos += 2; tracer_decoration_comment = tracer_decoration_comment_end_pos; @@ -860,8 +863,7 @@ void FCEUD_TraceInstruction(uint8 *opcode, int size) for(int i=0;i>2, - 'V'|(tmp&0x40)>>1, - 'U'|(tmp&0x20), - 'B'|(tmp&0x10)<<1, - 'D'|(tmp&0x08)<<2, - 'I'|(tmp&0x04)<<3, - 'Z'|(tmp&0x02)<<4, - 'C'|(tmp&0x01)<<5 - ); + char *s = str_procstatus; + *(s++) = X.P & 0x80 ? 'N' : 'n'; + *(s++) = X.P & 0x40 ? 'V' : 'v'; + *(s++) = X.P & 0x20 ? 'U' : 'u'; + *(s++) = X.P & 0x10 ? 'B' : 'b'; + *(s++) = X.P & 0x08 ? 'D' : 'd'; + *(s++) = X.P & 0x04 ? 'I' : 'i'; + *(s++) = X.P & 0x02 ? 'Z' : 'z'; + *(s++) = X.P & 0x01 ? 'C' : 'c'; + *(s++) = ' '; + *(s++) = '\0'; } if (logging_options & LOG_TO_THE_LEFT) { if (logging_options & LOG_REGISTERS) - strcat(str_result, str_axystate); + resSb << str_axystate; if (logging_options & LOG_PROCESSOR_STATUS) - strcat(str_result, str_procstatus); + resSb << str_procstatus; } if (logging_options & LOG_CODE_TABBING) { // add spaces at the beginning of the line according to stack pointer int spaces = (0xFF - X.S) & LOG_TABS_MASK; - for (int i = 0; i < spaces; i++) - str_tabs[i] = ' '; + std::memset(str_tabs, ' ', spaces); str_tabs[spaces] = 0; - strcat(str_result, str_tabs); + resSb << str_tabs; } else if (logging_options & LOG_TO_THE_LEFT) { - strcat(str_result, " "); + resSb << ' '; } if (logging_options & LOG_BANK_NUMBER) { if (addr >= 0x8000) - sprintf(str_address, "$%02X:%04X: ", getBank(addr), addr); + resSb << sb_addr(getBank(addr), 2) << ':' << sb_hex(addr, 4); else - sprintf(str_address, " $%04X: ", addr); + resSb << " " << sb_addr(addr); } else { - sprintf(str_address, "$%04X: ", addr); + resSb << sb_addr(addr); } - - strcat(str_result, str_address); - strcat(str_result, str_data); - strcat(str_result, str_disassembly); + + resSb << ": " << str_data; + resSb << str_disassembly; if (!(logging_options & LOG_TO_THE_LEFT)) { if (logging_options & LOG_REGISTERS) - strcat(str_result, str_axystate); + resSb << str_axystate; if (logging_options & LOG_PROCESSOR_STATUS) - strcat(str_result, str_procstatus); + resSb << str_procstatus; } OutputLogLine(str_result, &tempAddressesLog); @@ -978,9 +973,7 @@ void OutputLogLine(const char *str, std::vector* addressesLog, bool add_ { if (logtofile) { - fputs(str, LOG_FP); - if (add_newline) - fputs("\n", LOG_FP); + fileWriter.writeLine(str, add_newline); } else { if (add_newline) @@ -1025,7 +1018,7 @@ void EndLoggingSequence() { if (logtofile) { - fclose(LOG_FP); + fileWriter.close(); } else { strcpy(str_result, "Logging finished."); diff --git a/src/utils/StringBuilder.h b/src/utils/StringBuilder.h index 2c95e992..12fac0d0 100644 --- a/src/utils/StringBuilder.h +++ b/src/utils/StringBuilder.h @@ -59,6 +59,57 @@ public: return appendInt(intInfo.x, intInfo.minLen, intInfo.leadChar, intInfo.upperCase); } + // Append an array of characters that may or may not be null-terminated + StringBuilder &appendSubstr(const char *str, size_t maxLen) + { + size_t len = std::strlen(str), + copyLen = len <= maxLen ? len : maxLen; + + std::memcpy(end, str, copyLen); + end += len; + *end = '\0'; + + return *this; + } + + // Substitute for strncpy/strncat + // maxLen is the TOTAL size, including what's already built + // If alwaysAppendNull the last character will always be null + StringBuilder &appendStr(const char *str, size_t maxLen, bool alwaysAddNull = true) + { + size_t len = std::strlen(str), + curLen = size(), + lenLeft = maxLen - curLen; + + if (len < lenLeft) + { + std::memcpy(end, str, len + 1); + end += len; + } + else if (!alwaysAddNull) + { + // strncpy/strncat case: no terminating null + std::memcpy(end, str, lenLeft); + end += lenLeft; + } + else + { + // strncpy_s/strncat_s case: always null-terminate + if (lenLeft != 0) + { + size_t copyLen = lenLeft - 1; + std::memcpy(end, str, copyLen); + + end += copyLen; + *end = '\0'; + } + else + end[-1] = '\0'; + } + + return *this; + } + protected: inline StringBuilder &operator <<(nullptr_t) {