Add logging (#492)

* Add logger implementation for mgba debugging

* Add logging details to contributors guide

* Clang-format

* update docs real quick

* Cleanup for PR

* Update for PR

* Fix bad rebase

* Fix docs
This commit is contained in:
Rickey
2026-05-21 20:07:34 -07:00
committed by GitHub
parent c2844a5d32
commit d7414157a5
5 changed files with 152 additions and 1 deletions
+17
View File
@@ -143,6 +143,23 @@ In the repo we use custom scripts located in the [`scripts`](https://github.com/
## Debugging ## Debugging
It's recommended to use [mGBA](https://mgba.io/) for ROM testing and debugging. As it provides a [`gdbserver`](https://en.wikipedia.org/wiki/Gdbserver) via the `-g` flag `mgba -g build/balatro-gba.gba`. You can connect via `gdb` or here is a [great guide for vscode](https://felixjones.co.uk/mgba_gdb/vscode.html). It's recommended to use [mGBA](https://mgba.io/) for ROM testing and debugging. As it provides a [`gdbserver`](https://en.wikipedia.org/wiki/Gdbserver) via the `-g` flag `mgba -g build/balatro-gba.gba`. You can connect via `gdb` or here is a [great guide for vscode](https://felixjones.co.uk/mgba_gdb/vscode.html).
### Logging
Specifically for mgba, logging can be enabled. To do this set `MGBA_LOGGING=1` when running `make`:
```sh
MGBA_LOGGING=1 make
```
🟡 **Note**: If you don't see any logs, try running `make clean` before rebuilding
Then, you can enable logging via the `-l` or `--log-level` option:
```sh
mgba -l 7 build/balatro-gba.gba
```
See [`mgba_logger.h`](include/mgba_logger.h) for details on log levels.
## **Build Instructions** ## **Build Instructions**
<details> <details>
+4
View File
@@ -52,6 +52,10 @@ CFLAGS += $(GIT_C_FLAGS)
CFLAGS += $(INCLUDE) CFLAGS += $(INCLUDE)
ifeq ($(MGBA_LOGGING),1)
CFLAGS += -DMGBA_LOGGING
endif
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH) ASFLAGS := -g $(ARCH)
+73
View File
@@ -0,0 +1,73 @@
/**
* @file mgba_logger.h
*
* @brief Interface to interact with the mgba logger.
*
* Use with mgba in the command line.
*
* You can pass which logs you'd like to print with a flag passed to mgba
* with `-l` or `--log-level`.
*
* | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
* |---|---|---|-------|------|------|-------|-------|
* | / | / | / | DEBUG | INFO | WARN | ERROR | FATAL |
*
* ```sh
* mgba -l 3 game.rom # ERROR and FATAL
* mgba -l 14 game.rom # INFO, WARN, and ERROR
* ```
*
* @note You have to fight with other logs in mgba and DEBUG can get messy.
*
* @note FATAL does kill the game. Use with care.
*/
#ifndef MGBA_LOGGER_H
#define MGBA_LOGGER_H
#include <stdbool.h>
typedef enum
{
MGBA_LOG_FATAL,
MGBA_LOG_ERROR,
MGBA_LOG_WARN,
MGBA_LOG_INFO,
MGBA_LOG_DEBUG,
} MgbaLogLevel;
/**
* @brief Initialize mgba logger
*
* Checks that the logger is available by checking the expected registers
* magic number
*/
bool mgba_logger_init(void);
/**
* @brief Print to mgba log with a format string
*
* @param level
* @param fmt Format string
* @param ... variadic arguments
*
* @note for all logs, it's cutoff at the hard mgba limit of 0x100
*/
void mgba_printf(MgbaLogLevel level, const char* fmt, ...);
// clang-format off
#ifdef MGBA_LOGGING
#define MGBA_FATAL(...) mgba_printf(MGBA_LOG_FATAL, __VA_ARGS__)
#define MGBA_ERROR(...) mgba_printf(MGBA_LOG_ERROR, __VA_ARGS__)
#define MGBA_WARN(...) mgba_printf(MGBA_LOG_WARN, __VA_ARGS__)
#define MGBA_INFO(...) mgba_printf(MGBA_LOG_INFO, __VA_ARGS__)
#define MGBA_DEBUG(...) mgba_printf(MGBA_LOG_DEBUG, __VA_ARGS__)
#else
#define MGBA_FATAL(...) ((void)0)
#define MGBA_ERROR(...) ((void)0)
#define MGBA_WARN(...) ((void)0)
#define MGBA_INFO(...) ((void)0)
#define MGBA_DEBUG(...) ((void)0)
#endif
// clang-format on
#endif
+5 -1
View File
@@ -20,6 +20,7 @@
// Audio // Audio
#include "audio_utils.h" #include "audio_utils.h"
#include "mgba_logger.h"
#include "soundbank.h" #include "soundbank.h"
#include "soundbank_bin.h" #include "soundbank_bin.h"
@@ -31,6 +32,10 @@ void init()
irq_add(II_VBLANK, mmVBlank); irq_add(II_VBLANK, mmVBlank);
irq_add(II_HBLANK, affine_background_hblank); irq_add(II_HBLANK, affine_background_hblank);
#ifdef MGBA_LOGGING
mgba_logger_init();
#endif
// Initialize text engine // Initialize text engine
tte_init_se( tte_init_se(
0, 0,
@@ -86,7 +91,6 @@ void init()
REG_DISPCNT = DCNT_MODE1 | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_OBJ | DCNT_WIN0 | REG_DISPCNT = DCNT_MODE1 | DCNT_OBJ_1D | DCNT_BG0 | DCNT_BG1 | DCNT_BG2 | DCNT_OBJ | DCNT_WIN0 |
DCNT_WIN1; DCNT_WIN1;
// Initialize subsystems // Initialize subsystems
mmInitDefault((mm_addr)soundbank_bin, GBAL_MM_NUM_CHANNELS); mmInitDefault((mm_addr)soundbank_bin, GBAL_MM_NUM_CHANNELS);
load_options(); load_options();
+53
View File
@@ -0,0 +1,53 @@
#include "mgba_logger.h"
#ifdef MGBA_LOGGING
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <tonc.h>
#define MGBA_REG_DEBUG_ENABLE ((vu16*)0x4FFF780)
#define MGBA_REG_DEBUG_FLAGS ((vu16*)0x4FFF700)
#define MGBA_REG_DEBUG_STRING ((char*)0x4FFF600)
static const u32 MGBA_ENABLE_MAGIC = 0xC0DE;
static const u32 MGBA_ENABLE_OK = 0x1DEA;
static const u32 MGBA_LOG_SEND = 0x100;
static const u32 MGBA_LOG_BUFFER_SIZE = 0x100;
static bool mgba_logger_available = false;
bool mgba_logger_init(void)
{
*MGBA_REG_DEBUG_ENABLE = MGBA_ENABLE_MAGIC;
mgba_logger_available = (*MGBA_REG_DEBUG_ENABLE == MGBA_ENABLE_OK);
return mgba_logger_available;
}
void mgba_printf(MgbaLogLevel level, const char* fmt, ...)
{
if (!mgba_logger_available || fmt == NULL)
return;
va_list args;
va_start(args, fmt);
vsnprintf(MGBA_REG_DEBUG_STRING, MGBA_LOG_BUFFER_SIZE, fmt, args);
va_end(args);
*MGBA_REG_DEBUG_FLAGS = ((uint16_t)level & 0x7) | MGBA_LOG_SEND;
}
#else
// Noop stubs
bool mgba_logger_init(void)
{
return false;
}
void mgba_printf(MgbaLogLevel level, const char* fmt, ...)
{
}
#endif