/********************************************************************************
  debug.c: Debugger module version 1.1

	NINTENDO64 library

	 May 13, 1999
 ********************************************************************************/

/* modified by kawasedo */

#include "common.h"
#include <ultra64.h>
#include <PR/os_internal.h>
#include <stdarg.h>
#include <string.h>
#include "debug_ni.h"

#define _128
#define _64
#define _32
#define _16
#include "struct-rfc.inc"

#define	DEBUG_MESG_BREAK	((OSMesg)1)
#define	DEBUG_MESG_FAULT	((OSMesg)2)

#define	EXP_WATCH			23
#define	EXP_VCED			31

#define	RGBA16(r,g,b,a)		(((r)<<11)|((g)<< 6)|((b)<<1)|(a))

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


static DebugThread	debugger;				/* debugger record					*/

/********************************************************************************/
/*																				*/
/*	ASCII character table.														*/
/*																				*/
/********************************************************************************/

#define	FONT_COUNTX		5				/* font count x		*/
#define	FONT_WIDTH		6				/* font width 		*/
#define	FONT_HEIGHT		7				/* font height 		*/


#define		_NO			0xff
#define		_SP			0xff

#define		_w0			0
#define		_w1			1
#define		_w2			2
#define		_w3			3
#define		_w4			4
#define		_w5			5
#define		_w6			6
#define		_w7			7
#define		_w8			8
#define		_w9			9

#define		_wA			10
#define		_wB			11
#define		_wC			12
#define		_wD			13
#define		_wE			14
#define		_wF			15
#define		_wG			16
#define		_wH			17
#define		_wI			18
#define		_wJ			19
#define		_wK			20
#define		_wL			21
#define		_wM			22
#define		_wN			23
#define		_wO			24
#define		_wP			25
#define		_wQ			26
#define		_wR			27
#define		_wS			28
#define		_wT			29
#define		_wU			30	
#define		_wV			31
#define		_wW         32
#define		_wX			33
#define		_wY			34
#define		_wZ			35

#define		_CN			36		/*  .  */
#define		_KS			37		/*  (  */
#define		_KE			38		/*  )  */
#define		_MI			39		/*  -  */
#define		_QT			40		/*  ?  */
#define		_EM			41		/*  !  */
#define		_PL			42		/*  +  */
#define		_PA			43		/*  %  */
#define		_DT			44		/*  .  */


static u8 asciiTable[] = {
 	_NO,_NO,_NO,_NO,_NO,_NO,_NO,_NO,   	_NO,_NO,_NO,_NO,_NO,_NO,_NO,_NO,	/* 0x00 */
 	_NO,_NO,_NO,_NO,_NO,_NO,_NO,_NO,   	_NO,_NO,_NO,_NO,_NO,_NO,_NO,_NO,	/* 0x10 */
    _SP,_EM,_NO,_NO,_NO,_PA,_NO,_NO,    _KS,_KE,_NO,_PL,_NO,_MI,_DT,_NO,	/* 0x20 */
 	_w0,_w1,_w2,_w3,_w4,_w5,_w6,_w7,    _w8,_w9,_CN,_NO,_NO,_NO,_NO,_QT,	/* 0x30 */
 	_NO,_wA,_wB,_wC,_wD,_wE,_wF,_wG,  	_wH,_wI,_wJ,_wK,_wL,_wM,_wN,_wO,	/* 0x40 */
	_wP,_wQ,_wR,_wS,_wT,_wU,_wV,_wW,	_wX,_wY,_wZ,_NO,_NO,_NO,_NO,_NO,	/* 0x50 */
 	_NO,_wA,_wB,_wC,_wD,_wE,_wF,_wG,  	_wH,_wI,_wJ,_wK,_wL,_wM,_wN,_wO,	/* 0x60 */
	_wP,_wQ,_wR,_wS,_wT,_wU,_wV,_wW,	_wX,_wY,_wZ,_NO,_NO,_NO,_NO,_NO,	/* 0x70 */
};

/********************************************************************************/
/*																				*/
/*	Font data.																	*/
/*																				*/
/********************************************************************************/

static unsigned long fontData[] = {
	0x70871C30, 0x8988A250, 0x88808290, 0x88831C90, 0x888402F8, 0x88882210, 0x71CF9C10, 0xF9CF9C70,
	0x8228A288, 0xF200A288, 0x0BC11C78, 0x0A222208, 0x8A222288, 0x71C21C70, 0x23C738F8, 0x5228A480,
	0x8A282280, 0x8BC822F0, 0xFA282280, 0x8A28A480, 0x8BC738F8, 0xF9C89C08, 0x82288808, 0x82088808,
	0xF2EF8808, 0x82288888, 0x82288888, 0x81C89C70, 0x8A08A270, 0x920DA288, 0xA20AB288, 0xC20AAA88,
	0xA208A688, 0x9208A288, 0x8BE8A270, 0xF1CF1CF8, 0x8A28A220, 0x8A28A020, 0xF22F1C20, 0x82AA0220,
	0x82492220, 0x81A89C20, 0x8A28A288, 0x8A28A288, 0x8A289488, 0x8A2A8850, 0x894A9420, 0x894AA220,
	0x70852220, 0xF8011000, 0x08020800, 0x10840400, 0x20040470, 0x40840400, 0x80020800, 0xF8011000,
	0x70800000, 0x88822200, 0x08820400, 0x108F8800, 0x20821000, 0x00022200, 0x20800020, 0x00000000
};

/********************************************************************************/
/*																				*/
/*	Exception name.																*/
/*																				*/
/********************************************************************************/

static char *cpuExceptions[] = {
	"Interrupt",
	"TLB modification",
	"TLB exception on load",
	"TLB exception on store",
	"Address error on load",
	"Address error on store",
	"Bus error on inst.",
	"Bus error on data",
	"System call exception",
	"Breakpoint exception",
	"Reserved instruction",
	"Coprocessor unusable",
	"Arithmetic overflow",
	"Trap:",
	"Virtual coherency on inst.",
	"Floating point exception",
	"Watchpoint exception",
	"Virtual coherency on data"
};

static char *fpuExceptions[] = {
	"Unimplemented operation",
	"Invalid operation",
	"Division by zero",
	"Overflow",
	"Underflow",
	"Inexact operation"
};


/********************************************************************************/
/*																				*/
/*		Wait routine.															*/
/*																				*/
/********************************************************************************/
static void
WaitTime(long msec)
{
	OSTime endtime = OS_USEC_TO_CYCLES((u64)msec * 1000);

	osSetTime(0);
	while (osGetTime() < endtime);
}


/*////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//		Fault process.
//
//
//
//
//////////////////////////////////////////////////////////////////////////////////

/********************************************************************************/
/*																				*/
/*	Fill quarter rectangle														*/
/*																				*/
/********************************************************************************/
static void
QuarterRectangle(int posx, int posy, int width, int height)
{
	register int  cntx, cnty;
	register u16  *scrnptr;


	if (debugger.width == 640) {
		posx *= 2;  posy *= 2;  width *= 2;  height *= 2;
	}
	scrnptr = debugger.framebuf + debugger.width * posy + posx;

	for (cnty = 0; cnty < height; cnty++) {
		for (cntx = 0; cntx < width; cntx++) {
			*scrnptr = ((*scrnptr & RGBA16(0x1c,0x1c,0x1c,0)) >> 2) | 0x0001;
			scrnptr += 1;
		}
		scrnptr += debugger.width - width;
	}
}
/********************************************************************************/
/*																				*/
/*	Print a character.															*/
/*																				*/
/********************************************************************************/
static void
PrintCharacter(int posx, int posy, int code)
{
	register int	cntx, cnty;

	int		fontx   = (code % FONT_COUNTX) * FONT_WIDTH;
	int		fonty   = (code / FONT_COUNTX) * FONT_HEIGHT;
	u32 *	fontptr = &fontData[fonty];
	u16 *	scrnptr;


	if (debugger.width == 320) {
		scrnptr = debugger.framebuf + debugger.width * posy + posx;
		for (cnty = 0; cnty < FONT_HEIGHT; cnty++) {
			register u32 mask = 0x80000000 >> fontx;
			register u32 font = *fontptr++;

			for (cntx = 0; cntx < FONT_WIDTH; cntx++) {
				*scrnptr++ = (mask & font) ? RGBA16(31,31,31,1) : RGBA16(0,0,0,1);
				mask	 >>= 1;
			}
			scrnptr += debugger.width - FONT_WIDTH;
		}
	}
	else if (debugger.width == 640) {
		scrnptr = debugger.framebuf + 640*posy*2 + posx*2;

		for (cnty = 0; cnty < FONT_HEIGHT; cnty++) {
			register u32 mask = 0x80000000 >> fontx;
			register u32 font = *fontptr++;

			for (cntx = 0; cntx < FONT_WIDTH; cntx++) {
				u32 color = (mask & font) ? RGBA16(31,31,31,1) : RGBA16(0,0,0,1);

				*(scrnptr+  0) = color;
				*(scrnptr+  1) = color;
				*(scrnptr+640) = color;
				*(scrnptr+641) = color;

				scrnptr  += 2;
				mask	>>= 1;
			}
			scrnptr += 640*2 - FONT_WIDTH*2;
		}
	}
}
/********************************************************************************/
/*																				*/
/*	_Printf callback function.													*/
/*																				*/
/********************************************************************************/
static void *prout(void *string, const char *buffer, u32 length)
{
	return ((char *)memcpy(string, buffer, length) + length);
}
/********************************************************************************/
/*																				*/
/*	Print a string.																*/
/*																				*/
/********************************************************************************/
/* static void */
PUBLIC void PrintString(int posx, int posy, const char *format, ...)
{
	int		length;
	va_list vparam;
	char	*strp, string[256];


	va_start(vparam, format);
	if ((length = _Printf(&prout, string, format, vparam)) > 0) {

		for (strp = string; length > 0; length--, strp++){
			int	code = asciiTable[*strp & 0x7f];

			if (code != _SP)  PrintCharacter(posx, posy, code);
			posx += FONT_WIDTH;
		}
	}
	va_end(vparam);
}
/********************************************************************************/
/*																				*/
/*	Print a FPU register.														*/
/*																				*/
/********************************************************************************/
static void
PrintFPURegs(int posx, int posy, int regnum, float *data)
{
	u32	bits = *((u32 *)data);
	int exp  = ((bits & 0x7f800000) >> 23) - 127;


	if ((-126 <= exp && exp <= 127) || bits == 0) {
		PrintString(posx, posy, "F%02d:%+.3e", regnum, *data);
	} else {
		PrintString(posx, posy, "F%02d:---------", regnum);
	}
}
/********************************************************************************/
/*																				*/
/*	Print a FPU control status register.										*/
/*																				*/
/********************************************************************************/
static void
PrintFPUFlags(u32 fpcsr)
{
	int	index;
	u32	bitmask = 0x00020000;


	PrintString(30, 155, "FPCSR:%08XH", fpcsr);

	for (index = 0; index < 6; index++, bitmask >>= 1) {
		if (fpcsr & bitmask) {
			PrintString(132, 155, "(%s)", fpuExceptions[index]);
			break;
		}
	}
}
/********************************************************************************/
/*																				*/
/*	Print debug informations.													*/
/*																				*/
/********************************************************************************/
static void
PrintDebugInfo(OSThread *thread)
{
	__OSThreadContext *tc = &thread->context;
	short			  exc = (tc->cause >> 2) & 0x1f;
	int	print_y;
	char *msg = "(NO MSG)";
	static struct {
	  u32 value;
	  u8 x, y;
	  char name[2];
	} infopos[32] = {
	  {0,15 + 75 * 0,17,'P','C'},
	  {0,15 + 75 * 1,17,'A','T'},
	  {0,15 + 75 * 2,17,'V','A'},
	  {0,15 + 75 * 3,17,'S','R'},

	  {0,15 + 75 * 0,28,'A','0'},
	  {0,15 + 75 * 1,28,'A','1'},
	  {0,15 + 75 * 2,28,'A','2'},
	  {0,15 + 75 * 3,28,'A','3'},

	  {0,15 + 75 * 0,37,'V','0'},
	  {0,15 + 75 * 1,37,'V','1'},
	  {0,15 + 75 * 2,37,'T','0'},
	  {0,15 + 75 * 3,37,'T','1'},

	  {0,15 + 75 * 0,46,'T','2'},
	  {0,15 + 75 * 1,46,'T','3'},
	  {0,15 + 75 * 2,46,'T','4'},
	  {0,15 + 75 * 3,46,'T','5'},

	  {0,15 + 75 * 0,55,'T','6'},
	  {0,15 + 75 * 1,55,'T','7'},
	  {0,15 + 75 * 2,55,'T','8'},
	  {0,15 + 75 * 3,55,'T','9'},

	  {0,15 + 75 * 0,64,' ','A'}, /* s0 */
	  {0,15 + 75 * 1,64,' ','X'}, /* s1 */
	  {0,15 + 75 * 2,64,' ','Y'}, /* s2 */
	  {0,15 + 75 * 3,64,'P','C'}, /* s3 */

	  {0,15 + 75 * 0,73,'S','P'}, /* s4 */
	  {0,15 + 75 * 1,73,' ','Z'}, /* s5 */
	  {0,15 + 75 * 2,73,' ','C'}, /* s6 */
	  {0,15 + 75 * 3,73,' ','V'}, /* s7 */

	  {0,15 + 75 * 0,82,'F','P'},
	  {0,15 + 75 * 1,82,'G','P'},
	  {0,15 + 75 * 2,82,'S','P'},
	  {0,15 + 75 * 3,82,'R','A'},
	};
	int i, j;
	extern rfcstate_object *rfcstatep[];
	rfcstate_object *rfcp;

	osViSetXScale(1.0);
	osViSetYScale(1.0);

	if (exc == EXP_WATCH)  exc = 16; 
	if (exc == EXP_VCED )  exc = 17;

/* 	osWritebackDCacheAll(); */

	QuarterRectangle(15, 8, 291, 230);
	if (*(u32 *)0x80000000 > 0x80000000 && *(u32 *)0x80000000 < 0xa0000000
	    && exc == 0x0d
	    ) {
	  msg = (char *)*(u32 *)0x80000000;
	} else if (exc != 0x0d) {
	  msg = "";
	}
	PrintString(30,  9, "THREAD:%d %s %s", thread->id, cpuExceptions[exc], msg);

	infopos[0].value = tc->pc;
	infopos[1].value = tc->at;
	infopos[2].value = tc->badvaddr;
	infopos[3].value = tc->sr;

	infopos[4].value = tc->a0;
	infopos[5].value = tc->a1;
	infopos[6].value = tc->a2;
	infopos[7].value = tc->a3;

	infopos[8].value = tc->v0;
	infopos[9].value = tc->v1;
	infopos[10].value = tc->t0;
	infopos[11].value = tc->t1;

	infopos[12].value = tc->t2;
	infopos[13].value = tc->t3;
	infopos[14].value = tc->t4;
	infopos[15].value = tc->t5;

	infopos[16].value = tc->t6;
	infopos[17].value = tc->t7;
	infopos[18].value = tc->t8;
	infopos[19].value = tc->t9;

	infopos[20].value = tc->s0;
	infopos[21].value = tc->s1;
	infopos[22].value = tc->s2;
	infopos[23].value = tc->s3;

	infopos[24].value = tc->s4;
	infopos[25].value = tc->s5;
	infopos[26].value = tc->s6;
	infopos[27].value = tc->s7;

	infopos[28].value = tc->s8;
	infopos[29].value = tc->gp;
	infopos[30].value = tc->sp;
	infopos[31].value = tc->ra;

	for (i = 0; i < 32; i++) {
	  PrintString(infopos[i].x + 10, infopos[i].y, ":%08X", infopos[i].value);
	  PrintString(infopos[i].x, infopos[i].y, "%c%c", infopos[i].name[0], infopos[i].name[1]);
	}

	PrintString(10, 219, "s0-4:AXY PC SP s5-s7:ZCV gp:N t6:STORDONE t7:JTBL");
 	PrintString(10, 226, "                       t8:PAGEPTR t9:CYCL fp:WORK");

	rfcp = rfcstatep[0];
	
	PrintString(260, 10, "%d-FRM", rfcp -> emuframe);
	
	print_y = 92;

	if (0) {
	  extern u32 *debug_ptr;
	  osSyncPrintf("[%08x][PPU addr=%x]\n\n", *debug_ptr, rfcp -> ppu_addr);
	}

	if (0) {
	  extern u8 _codeSegmentEnd[];
	  extern int debug_value1, debug_value2, debug_value3;
	  PrintString(20, 150, "%08x %d %d %d", *(u32 *)_codeSegmentEnd,
		      debug_value1, debug_value2, debug_value3);
	}

#if 0
	if (rfcp) {
	  /* bank */
	  PrintString(15, print_y, "MBC(%04x)PB:%02x R2:%02x BKM:%02x PM:%02x RM:%02x",
		      rfcp -> mapper, rfcp -> pbank, rfcp -> mbc1_reg2, rfcp -> mbc1_bankmode, rfcp -> pbank_mask, rfcp -> rbank_mask);
	  print_y += 9;
	}

	if (1 && rfcp) {
	  /* page table */
	  int i;

	  for (i = 0; i < 0x10; i++) {
	    PrintString(30 + (i & 3) * 64, print_y + (i / 4) * 9, "%08x", rfcp -> page_table[i]);
	  }
	  print_y += (i / 4) * 9;
	}

	if (0 && rfcp) {
	  /* stack dump */
	  int address;
	  int i;

	  address = (tc -> DMG_SP) & 0xffe0; /* DMG_SP */
	  for (i = 0; i < 0x20; i++) {
	    if ((i & 0x0f) == 0) {
	      PrintString(15, print_y + (i / 0x10) * 8, "%04x:", address + i);
	    }
	    PrintString(45 + (i & 0x0f) * 15 + (i & 0x0c) / 2, print_y + (i / 0x10) * 8, "%02x",
			*(rfcp -> page_table[(address + i) / 0x1000] + address + i));
	  }
	  print_y += 18;
	}

	if (1 && rfcp) {
	  /* mem dump, memory dump */
	  int address;
	  int i;

	  address = 0xdef0;
	  for (i = 0; i < 0x10; i++) {
	    if ((i & 0x0f) == 0) {
	      PrintString(15, print_y + (i / 0x10) * 8, "%04x:", address + i);
	    }
	    PrintString(45 + (i & 0x0f) * 15 + (i & 0x0c) / 2, print_y + (i / 0x10) * 8, "%02x",
			*(rfcp -> page_table[(address + i) / 0x1000] + address + i));
	  }
	  print_y += ((i + 0x0f) / 0x10) * 8 + 2;
	}

	if (1) {
	  /* sgb pkt buf */

	  PrintString(20, print_y, "SGB%02x-%02x: %02X %02X%02X%02X %02X%02X%02X%02X "
		      "%02X%02X%02X%02X %02X%02X%02X%02X",
		      rfcp -> sgbpp_cnt, rfcp -> sgbpp_cnt_stop,
		      rfcp -> sgbpp_buf[0x0],
		      rfcp -> sgbpp_buf[0x1],
		      rfcp -> sgbpp_buf[0x2],
		      rfcp -> sgbpp_buf[0x3],
		      rfcp -> sgbpp_buf[0x4],
		      rfcp -> sgbpp_buf[0x5],
		      rfcp -> sgbpp_buf[0x6],
		      rfcp -> sgbpp_buf[0x7],
		      rfcp -> sgbpp_buf[0x8],
		      rfcp -> sgbpp_buf[0x9],
		      rfcp -> sgbpp_buf[0xa],
		      rfcp -> sgbpp_buf[0xb],
		      rfcp -> sgbpp_buf[0xc],
		      rfcp -> sgbpp_buf[0xd],
		      rfcp -> sgbpp_buf[0xe],
		      rfcp -> sgbpp_buf[0xf]);
	  print_y += 9;
	}

	if (rfcp) {
	  /* pc history, j = 0x4e $B$G(B 4 $B9T!"(B0xb2 $B$G(B 9 $B9T(B
	   * $B=E$J$i$J$$$h$&$K(B $B$G$-$k$@$1B?$/I=<($9$k(B
	   */
	  PrintString(7, print_y, "PCHIST:");
	  j = (((212 - print_y) / 9) * 10 + 9) * 2;
/* 	  j = 0xb2; */
	  for (i = j; i > 0; i -= 2) {
	    PrintString(20 + (i % 20) * 14, print_y + (i / 20) * 9, "%04x", rfcp -> pc_hist_buf[((rfcp -> pc_hist_offset - 2 - (j - i)) & 0xfe) / 2]);
	  }
	}
#endif

	
#if 0
	PrintFPUFlags(tc->fpcsr);

	PrintFPURegs( 30, 170,  0, &tc->fp0.f.f_even );
	PrintFPURegs(120, 170,  2, &tc->fp2.f.f_even );
	PrintFPURegs(210, 170,  4, &tc->fp4.f.f_even );
	PrintFPURegs( 30, 180,  6, &tc->fp6.f.f_even );
	PrintFPURegs(120, 180,  8, &tc->fp8.f.f_even );
	PrintFPURegs(210, 180, 10, &tc->fp10.f.f_even);
	PrintFPURegs( 30, 190, 12, &tc->fp12.f.f_even);
	PrintFPURegs(120, 190, 14, &tc->fp14.f.f_even);
	PrintFPURegs(210, 190, 16, &tc->fp16.f.f_even);
	PrintFPURegs( 30, 200, 18, &tc->fp18.f.f_even);
	PrintFPURegs(120, 200, 20, &tc->fp20.f.f_even);
	PrintFPURegs(210, 200, 22, &tc->fp22.f.f_even);
	PrintFPURegs( 30, 210, 24, &tc->fp24.f.f_even);
	PrintFPURegs(120, 210, 26, &tc->fp26.f.f_even);
	PrintFPURegs(210, 210, 28, &tc->fp28.f.f_even);
	PrintFPURegs( 30, 220, 30, &tc->fp30.f.f_even);
#endif
	
	osViBlack(FALSE);
	osViRepeatLine(FALSE);
	osViSwapBuffer(debugger.framebuf);

/* 	PrintString(210, 140, "MM:%08XH", *((u32*)tc->pc)); */
}
/********************************************************************************/
/*																				*/
/*	Find a faulted thread														*/
/*																				*/
/********************************************************************************/
static OSThread *
FindFaultedThread(void)
{
	OSThread * thread = __osGetActiveQueue();

	while (thread->priority != -1) {
		if (OS_PRIORITY_IDLE < thread->priority && thread->priority < OS_PRIORITY_APPMAX) {
			if (thread->flags & (OS_FLAG_CPU_BREAK|OS_FLAG_FAULT))  return(thread);
		}
		thread = thread->tlnext;
	}
	return(NULL);
}
/********************************************************************************/
/*																				*/
/*	Debug process main															*/
/*																				*/
/********************************************************************************/
static void
DebugProcess(void *argv)
{
	OSMesg	  event;
	OSThread *thread;


	osSetEventMesg(OS_EVENT_CPU_BREAK, &debugger.mesgque, DEBUG_MESG_BREAK);
	osSetEventMesg(OS_EVENT_FAULT	 , &debugger.mesgque, DEBUG_MESG_FAULT);

	do {
		osRecvMesg(&debugger.mesgque, (OSMesg *)&event, OS_MESG_BLOCK);
		thread = FindFaultedThread();
	} while (thread == NULL);

	osStopThread(thread);

	PrintDebugInfo(thread);
	while (1);		
	/* Halt	*/
}
/********************************************************************************/
/*																				*/
/*	Set debugger's frame buffer													*/
/*																				*/
/********************************************************************************/
extern void
DbSetFrameBuffer(void* framebuf, u16 width, u16 depth)
{
	debugger.framebuf = (u16*)K0_TO_K1(framebuf);
	debugger.width	  = width;
	debugger.depth	  = depth;
}
/********************************************************************************/
/*																				*/
/*	Start debugger thread														*/
/*																				*/
/********************************************************************************/
extern void
DbStartDebugger(void)
{
	debugger.framebuf = (u16*)PHYS_TO_K1(osMemSize) - (320*240);
	debugger.width	  = 320;
	debugger.depth	  =  16;

	osCreateMesgQueue(&debugger.mesgque, debugger.mesgbuf, DEBUG_NMESSAGES);
	osCreateThread(&debugger.thread, DEBUG_THREAD_ID, DebugProcess, NULL, debugger.stack+DEBUG_STACKSIZE64, OS_PRIORITY_APPMAX+1);
	osStartThread(&debugger.thread);
}
/********************************************************************************/
/*																				*/
/*	Print fatal error message													*/
/*																				*/
/********************************************************************************/
extern void
DbPrintFatalError(short posx, short posy, char* format, ...)
{
	int		length;
	va_list vparam;
	char	*strp, string[256];


	va_start(vparam, format);
	if ((length = _Printf(&prout, string, format, vparam)) > 0) {
		QuarterRectangle(posx-6, posy-6, (length+2)*6, 19);
		for (strp = string; length > 0; length--, strp++){
			int	code = asciiTable[*strp & 0x7f];

			if (code != _SP)  PrintCharacter(posx, posy, code);
			posx += FONT_WIDTH;
		}
	}
	va_end(vparam);
}
