2018-01-07 03:13:18 +01:00
# include <stdarg.h>
# include <stdio.h>
# include "gba/gba.h"
# include "config.h"
# define AGB_PRINT_FLUSH_ADDR 0x9FE209D
# define AGB_PRINT_STRUCT_ADDR 0x9FE20F8
# define AGB_PRINT_PROTECT_ADDR 0x9FE2FFE
# define WSCNT_DATA (WAITCNT_PHI_OUT_16MHZ | WAITCNT_WS0_S_2 | WAITCNT_WS0_N_4)
2018-01-10 01:28:32 +01:00
// originally for auto no$gba support, the string "no$gba" should be at this address,
// the user needs to read this string out as the memory viewer won't show it.
2018-01-09 03:39:07 +01:00
# define NOCASHGBAIDADDR 0x4FFFA00
2018-01-10 01:39:51 +01:00
# 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.
2018-01-07 03:13:18 +01:00
struct AGBPrintStruct
{
u16 m_nRequest ;
u16 m_nBank ;
u16 m_nGet ;
u16 m_nPut ;
} ;
typedef void ( * LPFN_PRINT_FLUSH ) ( void ) ;
2018-01-07 04:00:08 +01:00
# ifndef NDEBUG
2018-01-08 23:03:28 +01:00
2018-01-07 03:13:18 +01:00
void AGBPrintFlush1Block ( void ) ;
void AGBPrintInit ( void )
{
volatile struct AGBPrintStruct * pPrint = ( struct AGBPrintStruct * ) AGB_PRINT_STRUCT_ADDR ;
2021-11-10 23:01:21 +01:00
u16 * pWSCNT = & REG_WAITCNT ;
2018-01-07 03:13:18 +01:00
u16 * pProtect = ( u16 * ) AGB_PRINT_PROTECT_ADDR ;
u16 nOldWSCNT = * pWSCNT ;
* pWSCNT = WSCNT_DATA ;
* pProtect = 0x20 ;
pPrint - > m_nRequest = pPrint - > m_nGet = pPrint - > m_nPut = 0 ;
pPrint - > m_nBank = 0xFD ;
* pProtect = 0 ;
* pWSCNT = nOldWSCNT ;
}
static void AGBPutcInternal ( const char cChr )
{
volatile struct AGBPrintStruct * pPrint = ( struct AGBPrintStruct * ) AGB_PRINT_STRUCT_ADDR ;
u16 * pPrintBuf = ( u16 * ) ( 0x8000000 + ( pPrint - > m_nBank < < 16 ) ) ;
u16 * pProtect = ( u16 * ) AGB_PRINT_PROTECT_ADDR ;
u16 nData = pPrintBuf [ pPrint - > m_nPut / 2 ] ;
* pProtect = 0x20 ;
nData = ( pPrint - > m_nPut & 1 ) ? ( nData & 0xFF ) | ( cChr < < 8 ) : ( nData & 0xFF00 ) | cChr ;
pPrintBuf [ pPrint - > m_nPut / 2 ] = nData ;
pPrint - > m_nPut + + ;
* pProtect = 0 ;
}
void AGBPutc ( const char cChr )
{
2021-11-10 23:01:21 +01:00
u16 * pWSCNT = & REG_WAITCNT ;
2018-01-07 03:13:18 +01:00
u16 nOldWSCNT = * pWSCNT ;
volatile struct AGBPrintStruct * pPrint ;
* pWSCNT = WSCNT_DATA ;
AGBPutcInternal ( cChr ) ;
* pWSCNT = nOldWSCNT ;
pPrint = ( struct AGBPrintStruct * ) AGB_PRINT_STRUCT_ADDR ;
if ( pPrint - > m_nPut = = ( ( pPrint - > m_nGet - 1 ) & 0xFFFF ) )
AGBPrintFlush1Block ( ) ;
}
void AGBPrint ( const char * pBuf )
{
volatile struct AGBPrintStruct * pPrint = ( struct AGBPrintStruct * ) AGB_PRINT_STRUCT_ADDR ;
2021-11-10 23:01:21 +01:00
u16 * pWSCNT = & REG_WAITCNT ;
2018-01-07 03:13:18 +01:00
u16 nOldWSCNT = * pWSCNT ;
* pWSCNT = WSCNT_DATA ;
while ( * pBuf )
{
AGBPutc ( * pBuf ) ;
pBuf + + ;
}
* pWSCNT = nOldWSCNT ;
}
void AGBPrintf ( const char * pBuf , . . . )
{
char bufPrint [ 0x100 ] ;
va_list vArgv ;
va_start ( vArgv , pBuf ) ;
vsprintf ( bufPrint , pBuf , vArgv ) ;
va_end ( vArgv ) ;
AGBPrint ( bufPrint ) ;
}
static void AGBPrintTransferDataInternal ( u32 bAllData )
{
LPFN_PRINT_FLUSH lpfnFuncFlush ;
u16 * pIME ;
u16 nIME ;
u16 * pWSCNT ;
u16 nOldWSCNT ;
u16 * pProtect ;
volatile struct AGBPrintStruct * pPrint ;
pProtect = ( u16 * ) AGB_PRINT_PROTECT_ADDR ;
pPrint = ( struct AGBPrintStruct * ) AGB_PRINT_STRUCT_ADDR ;
lpfnFuncFlush = ( LPFN_PRINT_FLUSH ) AGB_PRINT_FLUSH_ADDR ;
2021-11-10 23:01:21 +01:00
pIME = & REG_IME ;
2018-01-07 03:13:18 +01:00
nIME = * pIME ;
2021-11-10 23:01:21 +01:00
pWSCNT = & REG_WAITCNT ;
2018-01-07 03:13:18 +01:00
nOldWSCNT = * pWSCNT ;
* pIME = nIME & ~ 1 ;
* pWSCNT = WSCNT_DATA ;
if ( bAllData )
{
while ( pPrint - > m_nPut ! = pPrint - > m_nGet )
{
* pProtect = 0x20 ;
lpfnFuncFlush ( ) ;
* pProtect = 0 ;
}
}
else if ( pPrint - > m_nPut ! = pPrint - > m_nGet )
{
* pProtect = 0x20 ;
lpfnFuncFlush ( ) ;
* pProtect = 0 ;
}
* pWSCNT = nOldWSCNT ;
* pIME = nIME ;
}
void AGBPrintFlush1Block ( void )
{
AGBPrintTransferDataInternal ( FALSE ) ;
}
void AGBPrintFlush ( void )
{
AGBPrintTransferDataInternal ( TRUE ) ;
}
void AGBAssert ( const char * pFile , int nLine , const char * pExpression , int nStopProgram )
{
if ( nStopProgram )
{
AGBPrintf ( " ASSERTION FAILED FILE=[%s] LINE=[%d] EXP=[%s] \n " , pFile , nLine , pExpression ) ;
AGBPrintFlush ( ) ;
asm ( " .hword 0xEFFF " ) ;
}
else
{
AGBPrintf ( " WARING FILE=[%s] LINE=[%d] EXP=[%s] \n " , pFile , nLine , pExpression ) ;
}
}
2018-01-09 04:03:07 +01:00
// no$gba print functions, uncomment to use
2018-01-07 03:13:18 +01:00
/*
2018-01-09 03:39:07 +01:00
void NoCashGBAPrint ( const char * pBuf )
2018-01-07 03:13:18 +01:00
{
2018-01-10 01:39:51 +01:00
* ( volatile u32 * ) NOCASHGBAPRINTADDR2 = ( u32 ) pBuf ;
2018-01-08 23:05:26 +01:00
}
2018-01-09 04:03:07 +01:00
void NoCashGBAPrintf ( const char * pBuf , . . . )
{
char bufPrint [ 0x100 ] ;
va_list vArgv ;
va_start ( vArgv , pBuf ) ;
vsprintf ( bufPrint , pBuf , vArgv ) ;
va_end ( vArgv ) ;
NoCashGBAPrint ( bufPrint ) ;
}
2018-01-08 23:05:26 +01:00
*/
2018-01-07 03:13:18 +01:00
# endif