Finish up

This commit is contained in:
TheRealQuantam 2024-02-21 18:38:00 -08:00
parent 8e7c6f68ff
commit 2b418e765e
4 changed files with 273 additions and 129 deletions

View File

@ -95,10 +95,21 @@ QString fceuGetOpcodeToolTip( uint8_t *opcode, int size );
QDialog *fceuCustomToolTipShow( const QPoint &globalPos, QDialog *popup ); QDialog *fceuCustomToolTipShow( const QPoint &globalPos, QDialog *popup );
// Faster replacement functions for sprintf // Faster replacement functions for sprintf. It's uglier, but much faster.
class StringBuilder class StringBuilder
{ {
public: public:
// Helper struct. Do not use directly.
template <unsigned Radix, typename T, typename Prefix = nullptr_t>
struct IntInfo
{
T x;
int minLen;
char leadChar;
bool upperCase;
Prefix prefix;
};
inline StringBuilder(char *str) : start(str), end(str) inline StringBuilder(char *str) : start(str), end(str)
{ {
*end = '\0'; *end = '\0';
@ -114,13 +125,7 @@ public:
return size_t(end - start); return size_t(end - start);
} }
template <class T> inline StringBuilder &operator <<(char ch)
inline StringBuilder &operator << (T value)
{
return append(value);
}
inline StringBuilder &append(char ch)
{ {
*(end++) = ch; *(end++) = ch;
*end = '\0'; *end = '\0';
@ -128,7 +133,7 @@ public:
return *this; return *this;
} }
inline StringBuilder &append(const char *src) inline StringBuilder &operator <<(const char *src)
{ {
size_t len = strlen(src); size_t len = strlen(src);
memcpy(end, src, len + 1); memcpy(end, src, len + 1);
@ -138,7 +143,20 @@ public:
return *this; return *this;
} }
template <unsigned Radix, class T> template<unsigned Radix, typename T, typename Prefix>
inline StringBuilder &operator <<(const IntInfo<Radix, T, Prefix> intInfo)
{
*this << intInfo.prefix;
return appendInt<Radix>(intInfo.x, intInfo.minLen, intInfo.leadChar, intInfo.upperCase);
}
protected:
inline StringBuilder &operator <<(nullptr_t)
{
return *this;
}
template<unsigned Radix, typename T>
StringBuilder &appendInt(T x, int minLen = 0, char leadChar = ' ', bool upperCase = false) StringBuilder &appendInt(T x, int minLen = 0, char leadChar = ' ', bool upperCase = false)
{ {
static_assert(Radix >= 2 && Radix <= 36, "Radix must be between 2 and 36"); static_assert(Radix >= 2 && Radix <= 36, "Radix must be between 2 and 36");
@ -195,38 +213,43 @@ public:
return *this; return *this;
} }
template <class T>
inline StringBuilder &appendDec(T x, int minLen = 0, char leadChar = ' ')
{
appendInt<10>(x, minLen, leadChar);
return *this;
}
template <class T>
inline StringBuilder &appendHex(T x, int minLen = 0, bool upperCase = true, char leadChar = '0')
{
appendInt<16>(x, minLen, leadChar, upperCase);
return *this;
}
template <class T>
inline StringBuilder &appendAddr(T addr, int minLen = 4, bool upperCase = true)
{
*(end++) = '$';
return appendHex(addr, minLen, upperCase);
}
template <class T>
inline StringBuilder &appendLit(T x, int minLen = 2, bool upperCase = true)
{
*(end++) = '#';
*(end++) = '$';
return appendHex(x, minLen, upperCase);
}
protected:
char *start; char *start;
char *end; char *end;
}; };
// Formatters for numbers
// Generic integer with any radius
template<unsigned Radix, typename T>
inline StringBuilder::IntInfo<Radix, T> sb_int(T x, int minLen = 0, char leadChar = ' ', bool upperCase = false)
{
return { x, minLen, leadChar, upperCase, nullptr };
}
// A decimal number
template <typename T>
inline StringBuilder::IntInfo<10, T> sb_dec(T x, int minLen = 0, char leadChar = ' ')
{
return { x, minLen, leadChar, false, nullptr };
}
// A hex number
template <typename T>
inline StringBuilder::IntInfo<16, T> sb_hex(T x, int minLen = 0, bool upperCase = true, char leadChar = '0')
{
return { x, minLen, leadChar, upperCase, nullptr };
}
// An address of the basic form $%x
template <typename T>
inline StringBuilder::IntInfo<16, T, char> sb_addr(T x, int minLen = 4, bool upperCase = true)
{
return { x, minLen, '0', upperCase, '$' };
}
// A literal value of the form #$%x
template <typename T>
inline StringBuilder::IntInfo<16, T, const char *> sb_lit(T x, int minLen = 2, bool upperCase = true)
{
return { x, minLen, '0', upperCase, "#$" };
}

View File

@ -62,7 +62,7 @@ debugSymbol_t *replaceSymbols( int flags, int addr, char *str )
if ( !sym || !( flags & ASM_DEBUG_REPLACE ) ) if ( !sym || !( flags & ASM_DEBUG_REPLACE ) )
{ {
(sb << '$').appendHex( addr, flags & ASM_DEBUG_ADDR_02X ? 2 : 4 ); sb << sb_addr( addr, flags & ASM_DEBUG_ADDR_02X ? 2 : 4 );
if ( sym ) if ( sym )
sb << ' '; sb << ' ';
@ -169,7 +169,7 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
if ( symDebugEnable ) if ( symDebugEnable )
sym = replaceSymbols( flags, tmp, stmp ); sym = replaceSymbols( flags, tmp, stmp );
(sb << chr << " (").appendAddr(opcode[1], 2) << ',' << indReg << ')'; sb << chr << " (" << sb_addr(opcode[1], 2) << ',' << indReg << ')';
if (showTrace) if (showTrace)
{ {
@ -177,9 +177,9 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
if (symDebugEnable) if (symDebugEnable)
sb << stmp; sb << stmp;
else else
sb.appendAddr(tmp); sb << sb_addr(tmp);
(sb << " = ").appendLit(GetMem(tmp)); sb << " = " << sb_lit(GetMem(tmp));
} }
break; break;
@ -216,10 +216,10 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
sb << stmp; sb << stmp;
} }
else else
sb.appendAddr(opcode[1], 2); sb << sb_addr(opcode[1], 2);
if (showTrace) if (showTrace)
(sb << " = ").appendLit(GetMem(opcode[1])); sb << " = " << sb_lit(GetMem(opcode[1]));
// ################################## End of SP CODE ########################### // ################################## End of SP CODE ###########################
break; break;
@ -238,7 +238,7 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
case 0xE0: chr = "CPX"; goto _immediate; case 0xE0: chr = "CPX"; goto _immediate;
case 0xE9: chr = "SBC"; goto _immediate; case 0xE9: chr = "SBC"; goto _immediate;
_immediate: _immediate:
(sb << chr << ' ').appendLit(opcode[1]); sb << chr << ' ' << sb_lit(opcode[1]);
break; break;
//Absolute //Absolute
@ -273,10 +273,10 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
sb << stmp; sb << stmp;
} }
else else
sb.appendAddr(tmp); sb << sb_addr(tmp);
if (showTrace) if (showTrace)
(sb << " = ").appendLit(GetMem(tmp)); sb << " = " << sb_lit(GetMem(tmp));
break; break;
@ -299,7 +299,7 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
sb << stmp; sb << stmp;
} }
else else
sb.appendAddr(tmp); sb << sb_addr(tmp);
break; break;
@ -345,16 +345,16 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
if ( symDebugEnable ) if ( symDebugEnable )
sym = replaceSymbols( flags, tmp, stmp ); sym = replaceSymbols( flags, tmp, stmp );
(sb << chr << ' ').appendAddr(opcode[1], 2) << ',' << indReg; sb << chr << ' ' << sb_addr(opcode[1], 2) << ',' << indReg;
if (showTrace) if (showTrace)
{ {
sb << " @ "; sb << " @ ";
if (symDebugEnable) if (symDebugEnable)
sb << stmp; sb << stmp;
else else
sb.appendAddr(tmp); sb << sb_addr(tmp);
(sb << " = ").appendLit(GetMem(tmp)); sb << " = " << sb_lit(GetMem(tmp));
} }
// ################################## End of SP CODE ########################### // ################################## End of SP CODE ###########################
break; break;
@ -383,7 +383,7 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
sb << stmp; sb << stmp;
} }
else else
sb.appendAddr(tmp); sb << sb_addr(tmp);
sb << ',' << indReg; sb << ',' << indReg;
@ -393,9 +393,9 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
if (symDebugEnable) if (symDebugEnable)
sb << stmp2; sb << stmp2;
else else
sb.appendAddr(tmp2); sb << sb_addr(tmp2);
(sb << " = ").appendLit(GetMem(tmp2)); sb << " = " << sb_lit(GetMem(tmp2));
} }
break; break;
@ -436,15 +436,15 @@ int DisassembleWithDebug(int addr, uint8_t *opcode, int flags, char *str, debugS
sb << stmp; sb << stmp;
} }
else else
sb.appendAddr(tmp); sb << sb_addr(tmp);
break; break;
case 0x6C: case 0x6C:
absolute(tmp); absolute(tmp);
(sb << "JMP (").appendAddr(tmp); sb << "JMP (" << sb_addr(tmp);
(sb << ") = ").appendAddr(GetMem(tmp) | GetMem(tmp + 1) << 8); sb << ") = " << sb_addr(GetMem(tmp) | GetMem(tmp + 1) << 8);
break; break;

View File

@ -4,6 +4,9 @@
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
// High-performance class for writing a series of text lines to a file, using overlapped, unbuffered I/O
// Works on Windows builds both SDL/Qt and non-SQL/Qt
// Apart from getLastError, the entire API can be adapted to other OS with no client changes
class TraceFileWriter class TraceFileWriter
{ {
public: public:
@ -13,6 +16,7 @@ public:
inline TraceFileWriter() inline TraceFileWriter()
{ {
// Windows Vista API that allows setting the end of file without closing and reopening it
HMODULE kernel32 = GetModuleHandleA("kernel32"); HMODULE kernel32 = GetModuleHandleA("kernel32");
SetFileInformationByHandle = kernel32 ? (SetFileInformationByHandlePtr)GetProcAddress(kernel32, "SetFileInformationByHandle") : nullptr; SetFileInformationByHandle = kernel32 ? (SetFileInformationByHandlePtr)GetProcAddress(kernel32, "SetFileInformationByHandle") : nullptr;
@ -30,14 +34,16 @@ public:
return isOpen; return isOpen;
} }
// SUPPOSED to always be valid (ERROR_SUCCESS if no error), but bugs may make it only valid after a failure
inline DWORD getLastError() const inline DWORD getLastError() const
{ {
return lastErr; return lastErr;
} }
// Open the file and allocate all necessary resources
bool open(const char *fileName, bool isPaused = false) bool open(const char *fileName, bool isPaused = false)
{ {
HANDLE file = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, NULL); HANDLE file = CreateFileA(fileName, GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, nullptr);
if (file == INVALID_HANDLE_VALUE) if (file == INVALID_HANDLE_VALUE)
{ {
lastErr = GetLastError(); lastErr = GetLastError();
@ -46,6 +52,7 @@ public:
initialize(false, isPaused, fileName, file); initialize(false, isPaused, fileName, file);
// Allocate resources
do do
{ {
for (unsigned i = 0; i < 2; i++) for (unsigned i = 0; i < 2; i++)
@ -70,11 +77,13 @@ public:
} while (false); } while (false);
if (!isOpen) if (!isOpen)
// Free resources on failure
cleanup(); cleanup();
return isOpen; return isOpen;
} }
// Close the file and free resources
void close() void close()
{ {
if (!isOpen) if (!isOpen)
@ -91,16 +100,19 @@ public:
cleanup(); cleanup();
} }
// When going from unpaused to paused, flush file and set end of file so it can be accessed externally
bool setPause(bool isPaused) bool setPause(bool isPaused)
{ {
if (isPaused && !this->isPaused) if (isPaused && !this->isPaused)
{ {
// Wait for any outstanding writes to complete
for (unsigned i = 0; i < 2; i++) for (unsigned i = 0; i < 2; i++)
{ {
if (!waitForBuffer(i)) if (!waitForBuffer(i))
return false; return false;
} }
// Write out anything still in the buffer
if (!writeTail()) if (!writeTail())
return false; return false;
} }
@ -111,6 +123,8 @@ public:
return true; return true;
} }
// 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)
{ {
if (!isOpen) if (!isOpen)
@ -119,20 +133,23 @@ public:
return false; return false;
} }
// Add to buffer
static const char eol[] = "\r\n";
size_t eolSize = strlen(eol);
char *buff = buffers[buffIdx]; char *buff = buffers[buffIdx];
OVERLAPPED *ovl = &ovls[buffIdx];
size_t lineLen = strlen(line); size_t lineLen = strlen(line);
if (buffOffs + lineLen + 1 > BuffSize) if (buffOffs + lineLen + eolSize > BuffSize)
{ {
// Buffer is full. This shouldn't ever happen.
lastErr = ERROR_INTERNAL_ERROR; lastErr = ERROR_INTERNAL_ERROR;
return false; return false;
} }
memcpy(buff + buffOffs, line, lineLen); memcpy(buff + buffOffs, line, lineLen);
buffOffs += lineLen; memcpy(buff + buffOffs + lineLen, eol, eolSize);
buff[buffOffs++] = '\n'; buffOffs += lineLen + eolSize;
// Check if the previous write is done, to detect it as early as possible
unsigned prevBuff = (buffIdx + 1) % 2; unsigned prevBuff = (buffIdx + 1) % 2;
if (!waitForBuffer(prevBuff, 0) && lastErr != ERROR_TIMEOUT) if (!waitForBuffer(prevBuff, 0) && lastErr != ERROR_TIMEOUT)
return false; return false;
@ -142,35 +159,45 @@ public:
if (buffOffs < FlushSize) if (buffOffs < FlushSize)
return true; return true;
DWORD writeSize = buffOffs - (buffOffs % BlockSize); return writeBlocks();
if (!beginWrite(writeSize)) }
// Flush buffer contents. Writes partial blocks, but does NOT set end of file
// Do NOT call frequently, as writes may be significantly undersized and cause poor performance
bool flush()
{
if (!isOpen)
{
lastErr = ERROR_FILE_NOT_FOUND;
return false;
}
// Write full blocks, if any
if (!writeBlocks())
return false; return false;
bool isAsync = bytesToWrite[buffIdx] != INVALID_FILE_SIZE; char *buff = buffers[buffIdx];
if (isAsync) if (buffOffs != 0)
{ {
if (!waitForBuffer(prevBuff)) // Write out partial block at the tail
size_t writeSize = (buffOffs + BlockSize - 1) & ~(BlockSize - 1);
memset(buff + buffOffs, ' ', writeSize - buffOffs);
if (!beginWrite(writeSize)
|| !waitForBuffer(buffIdx))
return false; return false;
// Switch to next buffer // Do NOT update buffIdx, buffOffs, or fileOffs, as the partial block must be overwritten later
memcpy(buffers[prevBuff], buff + writeSize, buffOffs - writeSize);
buffOffs -= writeSize;
fileOffs += writeSize;
buffIdx = prevBuff;
} }
else
// Wait for all writes to complete
for (unsigned i = 0; i < 2; i++)
{ {
// Stick with same buffer if (!waitForBuffer(i))
memmove(buff, buff + writeSize, buffOffs - writeSize); return false;
buffOffs -= writeSize;
} }
bytesToWrite[buffIdx] = INVALID_FILE_SIZE; lastErr = ERROR_SUCCESS;
return true; return true;
} }
@ -184,6 +211,8 @@ protected:
SetFileInformationByHandlePtr SetFileInformationByHandle; SetFileInformationByHandlePtr SetFileInformationByHandle;
const size_t NO_WRITE = size_t(-1);
DWORD lastErr; DWORD lastErr;
bool isOpen; bool isOpen;
@ -192,14 +221,16 @@ protected:
std::string fileName; std::string fileName;
HANDLE file; HANDLE file;
// Double-buffers
char *buffers[2]; char *buffers[2];
OVERLAPPED ovls[2]; OVERLAPPED ovls[2];
size_t bytesToWrite[2]; size_t bytesToWrite[2]; // Write in progress size or size_t(-1) if none
unsigned buffIdx; unsigned buffIdx;
size_t buffOffs; size_t buffOffs;
uint64_t fileOffs; uint64_t fileOffs;
// Put the class into a defined state, but does NOT allocate resources
void initialize(bool isOpen = false, bool isPaused = false, const char *fileName = "", HANDLE file = INVALID_HANDLE_VALUE) void initialize(bool isOpen = false, bool isPaused = false, const char *fileName = "", HANDLE file = INVALID_HANDLE_VALUE)
{ {
lastErr = ERROR_SUCCESS; lastErr = ERROR_SUCCESS;
@ -213,7 +244,7 @@ protected:
for (unsigned i = 0; i < 2; i++) for (unsigned i = 0; i < 2; i++)
{ {
buffers[i] = nullptr; buffers[i] = nullptr;
bytesToWrite[i] = INVALID_FILE_SIZE; bytesToWrite[i] = NO_WRITE;
} }
memset(ovls, 0, sizeof(ovls)); memset(ovls, 0, sizeof(ovls));
@ -223,6 +254,7 @@ protected:
fileOffs = 0; fileOffs = 0;
} }
// Close file and release resources. Does NOT wait for writes to complete.
void cleanup() void cleanup()
{ {
isOpen = false; isOpen = false;
@ -245,9 +277,52 @@ protected:
} }
} }
// Write out as many blocks as present in the buffer
bool writeBlocks()
{
if (buffOffs < BlockSize)
return true;
char *buff = buffers[buffIdx];
unsigned prevBuff = (buffIdx + 1) % 2;
OVERLAPPED *ovl = &ovls[buffIdx];
DWORD writeSize = buffOffs - (buffOffs % BlockSize);
if (!beginWrite(writeSize))
return false;
bool isAsync = bytesToWrite[buffIdx] != NO_WRITE;
if (isAsync)
{
if (!waitForBuffer(prevBuff))
return false; // Catastrophic failure case
// Switch to next buffer
memcpy(buffers[prevBuff], buff + writeSize, buffOffs - writeSize);
buffOffs -= writeSize;
fileOffs += writeSize;
buffIdx = prevBuff;
}
else
{
// Stick with same buffer
memmove(buff, buff + writeSize, buffOffs - writeSize);
buffOffs -= writeSize;
}
bytesToWrite[buffIdx] = NO_WRITE;
return true;
}
// Begin a write and handle errors without updating class state
bool beginWrite(size_t writeSize) bool beginWrite(size_t writeSize)
{ {
bytesToWrite[buffIdx] = INVALID_FILE_SIZE; bytesToWrite[buffIdx] = NO_WRITE;
if (writeSize % BlockSize != 0) if (writeSize % BlockSize != 0)
{ {
@ -281,21 +356,12 @@ protected:
return !lastErr; return !lastErr;
} }
bool writeTail() // Set the end of file so it can be accessed
bool setEndOfFile()
{ {
char *buff = buffers[buffIdx];
if (buffOffs != 0)
{
size_t writeSize = (buffOffs + BlockSize - 1) & ~(BlockSize - 1);
memset(buff + buffOffs, ' ', writeSize - buffOffs);
if (!beginWrite(writeSize)
|| !waitForBuffer(buffIdx))
return false;
}
if (SetFileInformationByHandle != nullptr) if (SetFileInformationByHandle != nullptr)
{ {
// Easy case: Vista or better
FILE_END_OF_FILE_INFO eofInfo; FILE_END_OF_FILE_INFO eofInfo;
eofInfo.EndOfFile.QuadPart = int64_t(fileOffs + buffOffs); eofInfo.EndOfFile.QuadPart = int64_t(fileOffs + buffOffs);
@ -304,29 +370,89 @@ protected:
lastErr = GetLastError(); lastErr = GetLastError();
return false; return false;
} }
}
return true; lastErr = ERROR_SUCCESS;
return true;
}
else
{
// Hard case: XP
// If set EOF fails, make a desperate attempt to reopen the file and keep running
lastErr = ERROR_SUCCESS;
do
{
// Set EOF to fileOffs rounded up to the next block
LARGE_INTEGER tgtOffs;
tgtOffs.QuadPart = (fileOffs + buffOffs + BlockSize - 1) & ~(BlockSize - 1);
LARGE_INTEGER newOffs;
if (!SetFilePointerEx(file, tgtOffs, &newOffs, FILE_BEGIN)
|| !SetEndOfFile(file))
break;
CloseHandle(file);
// Open file with buffering so the exact byte size can be set
tgtOffs.QuadPart = fileOffs + buffOffs;
file = CreateFile(fileName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
if (file != INVALID_HANDLE_VALUE)
{
if (!SetFilePointerEx(file, tgtOffs, &newOffs, FILE_BEGIN)
|| !SetEndOfFile(file))
lastErr = GetLastError();
CloseHandle(file);
}
else
lastErr = GetLastError();
// Finally, reopen the file in original mode
file = CreateFile(fileName.c_str(), GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING | FILE_FLAG_OVERLAPPED, nullptr);
if (file == INVALID_HANDLE_VALUE || lastErr)
break;
lastErr = ERROR_SUCCESS;
return true;
} while (false);
// Failed
if (!lastErr)
lastErr = GetLastError();
return false;
}
} }
// Write out everything in the buffer and set the file end for pausing
inline bool writeTail()
{
return flush() && setEndOfFile();
}
// Wait for an a buffer to become available, waiting for write completion if necessary
bool waitForBuffer(unsigned buffIdx, DWORD timeout = INFINITE) bool waitForBuffer(unsigned buffIdx, DWORD timeout = INFINITE)
{ {
if (buffIdx >= 2) if (buffIdx >= 2)
lastErr = ERROR_INTERNAL_ERROR; lastErr = ERROR_INTERNAL_ERROR;
else if (bytesToWrite[buffIdx] == INVALID_FILE_SIZE) else if (bytesToWrite[buffIdx] == NO_WRITE)
// No write in progress
lastErr = ERROR_SUCCESS; lastErr = ERROR_SUCCESS;
else else
{ {
// Wait for the operation to complete
DWORD waitRes = WaitForSingleObject(ovls[buffIdx].hEvent, timeout); DWORD waitRes = WaitForSingleObject(ovls[buffIdx].hEvent, timeout);
if (waitRes == WAIT_TIMEOUT) if (waitRes == WAIT_TIMEOUT)
lastErr = ERROR_TIMEOUT; lastErr = ERROR_TIMEOUT;
else if (waitRes != WAIT_OBJECT_0) else if (waitRes != WAIT_OBJECT_0)
{ {
lastErr = GetLastError(); lastErr = GetLastError();
bytesToWrite[buffIdx] = INVALID_FILE_SIZE; bytesToWrite[buffIdx] = NO_WRITE;
} }
else else
{ {
// Verify it succeeded
DWORD prevBytesWritten; DWORD prevBytesWritten;
if (!GetOverlappedResult(file, &ovls[buffIdx], &prevBytesWritten, FALSE)) if (!GetOverlappedResult(file, &ovls[buffIdx], &prevBytesWritten, FALSE))
lastErr = GetLastError(); lastErr = GetLastError();
@ -335,7 +461,7 @@ protected:
else else
lastErr = ERROR_SUCCESS; lastErr = ERROR_SUCCESS;
bytesToWrite[buffIdx] = INVALID_FILE_SIZE; bytesToWrite[buffIdx] = NO_WRITE;
} }
} }

View File

@ -915,15 +915,10 @@ traceRecord_t::traceRecord_t(void)
//---------------------------------------------------- //----------------------------------------------------
int traceRecord_t::appendAsmText(const char *txt) int traceRecord_t::appendAsmText(const char *txt)
{ {
int i = 0; size_t len = strlen(txt);
memcpy(asmTxt + asmTxtSize, txt, len + 1);
while (txt[i] != 0) asmTxtSize += len;
{
asmTxt[asmTxtSize] = txt[i];
i++;
asmTxtSize++;
}
asmTxt[asmTxtSize] = 0;
return 0; return 0;
} }
@ -961,26 +956,26 @@ int traceRecord_t::convToText(char *txt, int *len)
StringBuilder sb(txt + i); StringBuilder sb(txt + i);
if (skippedLines > 0) if (skippedLines > 0)
(sb << '(').appendDec(skippedLines) << " lines skipped) "; sb << '(' << sb_dec(skippedLines) << " lines skipped) ";
// Start filling the str_temp line: Frame count, Cycles count, Instructions count, AXYS state, Processor status, Tabs, Address, Data, Disassembly // Start filling the str_temp line: Frame count, Cycles count, Instructions count, AXYS state, Processor status, Tabs, Address, Data, Disassembly
if (logging_options & LOG_FRAMES_COUNT) if (logging_options & LOG_FRAMES_COUNT)
(sb << 'f').appendDec(frameCount, -6); sb << 'f' << sb_dec(frameCount, -6);
if (logging_options & LOG_CYCLES_COUNT) if (logging_options & LOG_CYCLES_COUNT)
(sb << 'c').appendDec(cycleCount, -11); sb << 'c' << sb_dec(cycleCount, -11);
if (logging_options & LOG_INSTRUCTIONS_COUNT) if (logging_options & LOG_INSTRUCTIONS_COUNT)
(sb << 'i').appendDec(instrCount, -11); sb << 'i' << sb_dec(instrCount, -11);
if (logging_options & LOG_REGISTERS) if (logging_options & LOG_REGISTERS)
{ {
StringBuilder sb(str_axystate); StringBuilder sb(str_axystate);
(sb << "A:").appendHex(cpu.A, 2); sb << "A:" << sb_hex(cpu.A, 2)
(sb << " X:").appendHex(cpu.X, 2); << " X:" << sb_hex(cpu.X, 2)
(sb << " Y:").appendHex(cpu.Y, 2); << " Y:" << sb_hex(cpu.Y, 2)
(sb << " S:").appendHex(cpu.S, 2); << " S:" << sb_hex(cpu.S, 2)
sb << ' '; << ' ';
} }
if (logging_options & LOG_PROCESSOR_STATUS) if (logging_options & LOG_PROCESSOR_STATUS)
@ -1020,24 +1015,24 @@ int traceRecord_t::convToText(char *txt, int *len)
if (logging_options & LOG_BANK_NUMBER) if (logging_options & LOG_BANK_NUMBER)
{ {
if (cpu.PC >= 0x8000) if (cpu.PC >= 0x8000)
sb.appendAddr((uint8_t)bank, 2) << ':'; sb << sb_addr((uint8_t)bank, 2) << ':';
else else
sb << " $"; sb << " $";
} }
else else
sb << '$'; sb << '$';
sb.appendHex(cpu.PC, 4) << ": "; sb << sb_hex(cpu.PC, 4) << ": ";
for (j = 0; j < opSize; j++) for (j = 0; j < opSize; j++)
sb.appendHex(opCode[j], 2) << ' '; sb << sb_hex(opCode[j], 2) << ' ';
for (; j < 3; j++) for (; j < 3; j++)
sb << " "; sb << " ";
sb << asmTxt; sb << asmTxt;
if (callAddr >= 0) if (callAddr >= 0)
(sb << " (from ").appendAddr((uint16_t)callAddr) << ')'; sb << " (from " << sb_addr((uint16_t)callAddr) << ')';
if (!(logging_options & LOG_TO_THE_LEFT)) if (!(logging_options & LOG_TO_THE_LEFT))
{ {