In order to handle the self-assign case, string::operator= moves the string, which may copy the string in reverse. The MGBA string register does not allow this I believe. In order to avoid this, it now uses a raw character buffer and is copied using string_view::copy. string_view::copy will always copy the string forward.
57 lines
1.3 KiB
C++
57 lines
1.3 KiB
C++
#include "debug.hpp"
|
|
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
|
|
#include <tonc.h>
|
|
|
|
#include <mtl/string.hpp>
|
|
#include <mtl/string_view.hpp>
|
|
|
|
namespace debug {
|
|
/**
|
|
* \brief MGBA debug registers and constants
|
|
*/
|
|
namespace reg {
|
|
/**
|
|
* \brief MGBA debug enable register.
|
|
*
|
|
* When 0xC0DE is written to the register, debug output is enabled.
|
|
* When 0 is written to the register, debug output is disabled.
|
|
* Will be set to 0x1DEA when successfully enabled.
|
|
*/
|
|
static volatile uint16_t& enable = *reinterpret_cast<uint16_t*>(0x4FFF780);
|
|
/**
|
|
* \brief MGBA debug flags register.
|
|
*/
|
|
static volatile uint16_t& flags = *reinterpret_cast<uint16_t*>(0x4FFF700);
|
|
/**
|
|
* \brief MGBA debug string register.
|
|
*
|
|
* Max length of 0x100 (256) including null terminator.
|
|
*/
|
|
static char* string = reinterpret_cast<char*>(0x4FFF600);
|
|
constexpr static size_t string_len = 255;
|
|
}; // namespace reg
|
|
|
|
void puts(const mtl::string_view& msg, level lvl) {
|
|
size_t count = msg.length();
|
|
if (count > reg::string_len) { count = reg::string_len; }
|
|
|
|
// Must be copied manually because the MGBA string register does
|
|
// not allow copying in reverse (I think)
|
|
msg.copy(reg::string, count);
|
|
reg::flags = lvl | 0x100;
|
|
}
|
|
|
|
bool open() {
|
|
reg::enable = 0xC0DE;
|
|
return reg::enable == 0x1DEA;
|
|
}
|
|
|
|
void close() {
|
|
reg::enable = 0;
|
|
}
|
|
}; // namespace debug
|