#include <ultra64.h>
#include <stdio.h>
#include <ctype.h>
#include <stdarg.h>

/*
   Intelligent Systems Co.,Ltd.

   _IS_MSGBUFFER_AD,_IS_MSGBUFFER_LEN is a communication buffer address/buffer for debug print.  If a problem arises in the location etc, it can be moved by 4K unit.  Extending over 64K segment is not allowed.  
    (For example, from 0xb1f88000 to 0xb1f98000, etc.)
   And, if this is changed, it is necessary to set to the address which corresponds to the setting of the host side.  Any operation without these conditions are not guaranteed. Also, do not change any values other than _IS_MSGBUFFER_AD,_IS_MSGBUFFER_LEN.   

   Default address: _IS_MSGBUFFER_AD  = 0xb1ff0000
   Default size  : _IS_MSGBUFFER_LEN = 0x10000
*/
#define _IS_MSGBUFFER_AD    0xb1ff0000      /* 32Mbyte RAM bottom   */
#define _IS_MSGBUFFER_LEN   0x10000         /* bbuffer length   */



#define _IS_MSGBUF_HEADLEN  0x20
#define _IS_MSGBUF_CHKAD    (_IS_MSGBUFFER_AD+0x00)     /* V810->N64  "IS64"        */
#define _IS_MSGBUF_GETPT    (_IS_MSGBUFFER_AD+0x04)     /* V810->N64  get pt        */
#define _IS_MSGBUF_PUTPT    (_IS_MSGBUFFER_AD+0x14)     /* N64->V810  put pt        */
#define _IS_MSGBUF_MSGTOP   (_IS_MSGBUFFER_AD+_IS_MSGBUF_HEADLEN)

#define _IS_MSGBUF_CHK_CODE (('I'<<24)+('S'<<16)+('6'<<8)+'4')

#if 1   /* normal 1 */
#define _is_WriteIo osPiWriteIo
#define _is_ReadIo osPiReadIo
#else   /* isPrintf debug */
#define _IS_MSGBUFFER_AD    0x800f0000
#define _is_WriteIo TestWrite
#define _is_ReadIo TestRead
TestRead(int ad, int *dt)
{ *dt = *(int *)ad; }
TestWrite(int ad, int dt)
{ *(int *)ad    = dt; }
#endif


void isPrintfInit(void)
{
    _is_WriteIo(_IS_MSGBUF_PUTPT, 0);
    _is_WriteIo(_IS_MSGBUF_GETPT, 0);
    _is_WriteIo(_IS_MSGBUF_CHKAD, _IS_MSGBUF_CHK_CODE);
}

static void *_is_printf_s(void *, const char *, int);

extern void _Printf(void (*)(void *), int, const char *, va_list);

void isPrintf(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    _Printf((void(*)(void *))_is_printf_s, 0, fmt, ap);
    va_end(ap);
}
void osSyncPrintf(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    _Printf((void(*)(void *))_is_printf_s, 0, fmt, ap);
    va_end(ap);
}
void rmonPrintf(const char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    _Printf((void(*)(void *))_is_printf_s, 0, fmt, ap);
    va_end(ap);
}

static void *_is_printf_s(void *str, register const char *buf, register int n)
{
    u32             dt;
    register int    putad, getad, newad;
    register int    sft, ad;

    _is_ReadIo(_IS_MSGBUF_CHKAD, &dt);
    if (dt != _IS_MSGBUF_CHK_CODE) return((void *)1);

    _is_ReadIo(_IS_MSGBUF_GETPT, &dt); getad = dt;
    _is_ReadIo(_IS_MSGBUF_PUTPT, &dt); putad = dt;
    newad = putad + n;
    if (newad >= (_IS_MSGBUFFER_LEN - _IS_MSGBUF_HEADLEN)) {
        newad -= (_IS_MSGBUFFER_LEN - _IS_MSGBUF_HEADLEN);
        if ((getad < (newad)) || (getad > putad)) return((void *)1);
    } else {
        if ((getad > putad) && (getad < (newad))) return((void *)1);
    }

    while(n) {
        if (*buf) {
            sft = (3 - (putad & 0x03)) << 3;
            ad = _IS_MSGBUF_MSGTOP+(putad & 0x0ffffffc);
            _is_ReadIo(ad, &dt);
            _is_WriteIo(ad, (dt & (~(0xff << sft)))|(*buf << sft));
            putad++;
            if (putad >= (_IS_MSGBUFFER_LEN - _IS_MSGBUF_HEADLEN)) putad -= (_IS_MSGBUFFER_LEN - _IS_MSGBUF_HEADLEN);
        }
        buf++;
        n--;
    }
    _is_WriteIo(_IS_MSGBUF_PUTPT, putad);
    return((void *)1);
}

