[debug] add support for mgba printf

* adds support for mgba printf debugging as well as adding support for switching between debugging configuration
* adds `mini_printf` as an alternative to libc printf as well as switches to choose a pretty printing handler
* adds a pretty printing format to `mini_printf` to print preproc encoded strings
This commit is contained in:
sbird
2022-09-06 13:40:29 +02:00
parent 7dac3c4b65
commit 584bfe0221
6 changed files with 605 additions and 42 deletions
+129 -5
View File
@@ -2,6 +2,8 @@
#include <stdio.h>
#include "gba/gba.h"
#include "config.h"
#include "malloc.h"
#include "mini_printf.h"
#define AGB_PRINT_FLUSH_ADDR 0x9FE209D
#define AGB_PRINT_STRUCT_ADDR 0x9FE20F8
@@ -14,6 +16,11 @@
#define NOCASHGBAPRINTADDR1 0x4FFFA10 // automatically adds a newline after the string has finished
#define NOCASHGBAPRINTADDR2 0x4FFFA14 // does not automatically add the newline. by default, NOCASHGBAPRINTADDR2 is used. this is used to keep strings consistent between no$gba and VBA-RR, but a user can choose to forgo this.
// hardware extensions for LOG_HANDLER_MGBA_PRINT
#define REG_DEBUG_ENABLE ((vu16*) (0x4FFF780)) // handshake: (w)[0xC0DE] -> (r)[0x1DEA]
#define REG_DEBUG_FLAGS ((vu16*) (0x4FFF700))
#define REG_DEBUG_STRING ((char*) (0x4FFF600))
struct AGBPrintStruct
{
u16 m_nRequest;
@@ -26,6 +33,8 @@ typedef void (*LPFN_PRINT_FLUSH)(void);
#ifndef NDEBUG
// AGBPrint print functions
#if (LOG_HANDLER == LOG_HANDLER_AGB_PRINT)
void AGBPrintFlush1Block(void);
void AGBPrintInit(void)
@@ -87,7 +96,13 @@ void AGBPrintf(const char *pBuf, ...)
char bufPrint[0x100];
va_list vArgv;
va_start(vArgv, pBuf);
vsprintf(bufPrint, pBuf, vArgv);
#if (PRETTY_PRINT_HANDLER == PRETTY_PRINT_MINI_PRINTF)
mini_vsnprintf(bufPrint, 0x100, pBuf, vArgv);
#elif (PRETTY_PRINT_HANDLER == PRETTY_PRINT_LIBC)
vsnprintf(bufPrint, 0x100, pBuf, vArgv);
#else
#error "unspecified pretty printing handler."
#endif
va_end(vArgv);
AGBPrint(bufPrint);
}
@@ -155,9 +170,10 @@ void AGBAssert(const char *pFile, int nLine, const char *pExpression, int nStopP
AGBPrintf("WARING FILE=[%s] LINE=[%d] EXP=[%s] \n", pFile, nLine, pExpression);
}
}
#endif
// no$gba print functions, uncomment to use
/*
// no$gba print functions
#if (LOG_HANDLER == LOG_HANDLER_NOCASH_PRINT)
void NoCashGBAPrint(const char *pBuf)
{
*(volatile u32 *)NOCASHGBAPRINTADDR2 = (u32)pBuf;
@@ -168,10 +184,118 @@ void NoCashGBAPrintf(const char *pBuf, ...)
char bufPrint[0x100];
va_list vArgv;
va_start(vArgv, pBuf);
vsprintf(bufPrint, pBuf, vArgv);
#if (PRETTY_PRINT_HANDLER == PRETTY_PRINT_MINI_PRINTF)
mini_vsnprintf(bufPrint, 0x100, pBuf, vArgv);
#elif (PRETTY_PRINT_HANDLER == PRETTY_PRINT_LIBC)
vsnprintf(bufPrint, 0x100, pBuf, vArgv);
#else
#error "unspecified pretty printing handler."
#endif
va_end(vArgv);
NoCashGBAPrint(bufPrint);
}
*/
void NoCashGBAAssert(const char *pFile, s32 nLine, const char *pExpression, bool32 nStopProgram)
{
if (nStopProgram)
{
NoCashGBAPrintf("ASSERTION FAILED FILE=[%s] LINE=[%d] EXP=[%s]", pFile, nLine, pExpression);
asm(".hword 0xEFFF");
}
else
{
NoCashGBAPrintf("WARING FILE=[%s] LINE=[%d] EXP=[%s]", pFile, nLine, pExpression);
}
}
#endif
// mgba print functions
#if (LOG_HANDLER == LOG_HANDLER_MGBA_PRINT)
#define MGBA_PRINTF_BUFFER_SIZE (4096)
#define MGBA_LOG_FATAL (0)
#define MGBA_LOG_ERROR (1)
#define MGBA_LOG_WARN (2)
#define MGBA_LOG_INFO (3)
#define MGBA_LOG_DEBUG (4)
#define MGBA_REG_DEBUG_MAX (256)
bool32 MgbaOpen(void)
{
*REG_DEBUG_ENABLE = 0xC0DE;
return *REG_DEBUG_ENABLE == 0x1DEA;
}
void MgbaClose(void)
{
*REG_DEBUG_ENABLE = 0;
}
static void MgbaPrintfBounded(s32 level, const char* ptr, ...)
{
va_list args;
level &= 0x7;
va_start(args, ptr);
#if (PRETTY_PRINT_HANDLER == PRETTY_PRINT_MINI_PRINTF)
mini_vsnprintf(REG_DEBUG_STRING, MGBA_REG_DEBUG_MAX, ptr, args);
#elif (PRETTY_PRINT_HANDLER == PRETTY_PRINT_LIBC)
vsnprintf(REG_DEBUG_STRING, MGBA_REG_DEBUG_MAX, ptr, args);
#else
#error "unspecified pretty printing handler."
#endif
va_end(args);
*REG_DEBUG_FLAGS = level | 0x100;
}
void MgbaPrintf(const char* ptr, ...)
{
va_list args;
u32 offset = 0;
u32 n = 0;
u32 i;
char *buffer = Alloc(MGBA_PRINTF_BUFFER_SIZE);
AGB_ASSERT(buffer != NULL);
va_start(args, ptr);
#if (PRETTY_PRINT_HANDLER == PRETTY_PRINT_MINI_PRINTF)
n = mini_vsnprintf(buffer, MGBA_PRINTF_BUFFER_SIZE, ptr, args);
#elif (PRETTY_PRINT_HANDLER == PRETTY_PRINT_LIBC)
n = vsnprintf(buffer, MGBA_PRINTF_BUFFER_SIZE, ptr, args);
#else
#error "unspecified pretty printing handler."
#endif
va_end(args);
AGB_ASSERT(n < MGBA_PRINTF_BUFFER_SIZE);
do
{
for (i = 0; i < MGBA_REG_DEBUG_MAX; ++i)
{
REG_DEBUG_STRING[i] = buffer[offset + i];
if (buffer[offset + i] == 0)
break;
}
offset += i;
*REG_DEBUG_FLAGS = MGBA_LOG_INFO | 0x100;
} while ((i == MGBA_REG_DEBUG_MAX) && (buffer[offset] != '\0'));
Free(buffer);
}
void MgbaAssert(const char *pFile, s32 nLine, const char *pExpression, bool32 nStopProgram)
{
if (nStopProgram)
{
MgbaPrintfBounded(MGBA_LOG_ERROR, "ASSERTION FAILED FILE=[%s] LINE=[%d] EXP=[%s]", pFile, nLine, pExpression);
asm(".hword 0xEFFF");
}
else
{
MgbaPrintfBounded(MGBA_LOG_WARN, "WARING FILE=[%s] LINE=[%d] EXP=[%s]", pFile, nLine, pExpression);
}
}
#endif
#endif