/*****************************************************
debug.c : Edited at 1998,3,4 by K.Sasaki
		Revised at 2019,3,16 by K.Sasaki
		Revised at 2020,1,7 by K.Sasaki
		Revised at 2023,2,28 by K.Sasaki
		Revised at 2026,2,28 by K.Sasaki	for V1.04
  μITRON サンプルプログラム
  Copyright(C) 1998-2026 佐々木芳

デバグタスク
	デバグポートを使ってホスト（ＰＣ）と接続し、コマンドライン
	インタプリタ(CLI)として動作する。

  処理概要
  ・コマンド入力処理
		ホストからのデータをコマンドバッファに取り込み、<CR>を受け取った
		段階で、コマンドの解析、実行を行う。
		実行できないときは NG [エラーメッセージ] <CR> を
		実行できたときは OK [戻り値] <CR> を返します。
		未定義コマンドの場合は、 NG : Unknown command name.<CR> を返す。

*****************************************************/
#ifdef _CMTOY
#define _CRT_SECURE_NO_WARNINGS
#endif

#include "hal.h"
#include "hal_systembus.h"
#include "itron.h"
#include "kernel_id.h"
#include "debug.h"
#include <stdio.h>
#include <stdarg.h>
//#include <string.h>
//#include <ctype.h>


/*プログラム名とバージョン*/
char prog_ver[] = "Debug CLI, V1.04" NEWLINE;


/*関数プロトタイプ*/
void VersionCommand(char* s);		/*verコマンド*/
void MemoryCommand(char* s);		/*memコマンド*/
void ModeCommand(char* s);			/*modeコマンド*/
void HelpCommand(char* s);			/*helpコマンド*/
void DumpByteCommand(char* s);		/*dコマンド*/
void DumpWordCommand(char* s);		/*dwコマンド*/
void DumpDWordCommand(char* s);		/*ddコマンド*/
void SubstituteCommand(char* p);	/*sコマンド*/
void SubstituteWordCommand(char* p);/*swコマンド*/
void SubstituteDWordCommand(char* p);/*sdコマンド*/
void InbyteCommand(char* s);		/*inbyteコマンド*/
void OutbyteCommand(char* s);		/*outbyteコマンド*/
void InwordCommand(char* s);		/*inwordコマンド*/
void OutwordCommand(char* s);		/*outwordコマンド*/
void IndwordCommand(char* s);		/*indwordコマンド*/
void OutdwordCommand(char* s);		/*outdwordコマンド*/
void TskStsCommand(char* s);		/*tskコマンド*/
void SemStsCommand(char* s);		/*semコマンド*/
void FlgStsCommand(char* s);		/*flgコマンド*/
void MbxStsCommand(char* s);		/*mbxコマンド*/
void MpfStsCommand(char* s);		/*mpfコマンド*/
//void GetTraceCommand(char* s);		/*trcコマンド*/

void LargeToSmall(char* s);			/*小文字変換*/

BOOL GetDwordOpParameter(char *s, DWORD *pDword, char* op);
BOOL GetDwordParameter(char *s, DWORD *pDword);
BOOL GetAddressParameter(char *s, DWORD *pAddr);
void PrintTaskInfo(ID tskid, T_RTSK *pTI);
const char* GetTaskName(T_RTSK *ptskinfo);
void PrintBlank(int splen);

typedef void (*PFNCOMMAND)(char* p);	/*コマンド処理関数形式*/
typedef struct tagCommandTabel{
	char command_name[12];
	PFNCOMMAND exec;
}COMMANDTABLE;
/*コマンド表*/
COMMANDTABLE CommandTable[]={
		{"ver",		VersionCommand},		/*versionコマンド*/
		{"mem",		MemoryCommand},			/*memoryコマンド*/
		{"mode",	ModeCommand},			/*modeコマンド*/
		{"help",	HelpCommand},			/*helpコマンド*/
		{"d",		DumpByteCommand},		/*dコマンド*/
		{"dw",		DumpWordCommand},		/*dwコマンド*/
		{"dd",		DumpDWordCommand},		/*ddコマンド*/
		{"s",		SubstituteCommand},		/*sコマンド*/
		{"sw",		SubstituteWordCommand},	/*swコマンド*/
		{"sd",		SubstituteDWordCommand},/*sdコマンド*/
		{"inb",		InbyteCommand},			/*inbコマンド*/
		{"inw",		InwordCommand},			/*inwコマンド*/
		{"ind",		IndwordCommand},		/*indコマンド*/
		{"outb",	OutbyteCommand},		/*outbコマンド*/
		{"outw",	OutwordCommand},		/*outwコマンド*/
		{"outd",	OutdwordCommand},		/*outdコマンド*/
		{"tsk",		TskStsCommand},			/*tskコマンド*/
		{"sem",		SemStsCommand},			/*semコマンド*/
		{"flg",		FlgStsCommand},			/*flgコマンド*/
		{"mbx",		MbxStsCommand},			/*mbxコマンド*/
		{"mpf",		MpfStsCommand},			/*mplコマンド*/
//		{"trc",		GetTraceCommand},		/*trcコマンド*/
		{"",		NULL}
};

/*カスタムコマンド処理関数*/
PFN_CUSTOM_COMMAND	pfnCustomCommandProc;

void DebugSetCustomCommandProc(PFN_CUSTOM_COMMAND pfnProc)
{
	pfnCustomCommandProc = pfnProc;
}

BOOL	g_MemoeyDefined;
TARGET_MEMORY_SPEC	g_MemorySpec;
BOOL IsWA()
{
	g_MemoeyDefined = halInqTargetMemorySpec(&g_MemorySpec);
	if(g_MemoeyDefined){
		if(g_MemorySpec.MemCell == M_CELL16) return TRUE;//ワードアドレッシング
	}
	return FALSE;
}

//
DWORD NextAddr(DWORD addr, int byte_offset)
{
	if(IsWA()){
		addr = addr + byte_offset/2;
	}else{
		addr = addr + byte_offset;
	}
	return addr;
}




/*変数*/
char CLIBuffer[1024];			/*コマンドバッファ*/
static const char Separators[] = " \t\r";		/*区切りコード*/
enum { Echo, NoEcho } EchoMode;

/*タスク*/
void DebugTask(VP_INT exinf){
	int	i;
	char* p;
	WORD  c;
	
	/*デバグコンソールの初期化*/
	/*DebugInitConsole(DP_CON0);初期化タスクで行う*/
	CMTRACE("DebugTask: 開始\n");

	EchoMode = Echo;
	DebugPrintf(NEWLINE "%s", prog_ver);
	while(1){
		tslp_tsk(20);
		//halDebugPrintf("RS STATUS = %02x\n", halSerialGetStatus(0));
		c = DebugSenseChar();
		if(c == 0x09){/*TAB キー*/
			int len = 0;
			CC_RESULT result = 0;
			/*ESCキーを検出したらプロンプトを表示して1行入力待ち*/
			DebugPutString("CLI> ");		/**/
			len = DebugWaitCommand();
			/*コマンド解析*/
			if((len > 0) && (CLIBuffer[0] == '.')){
				if(pfnCustomCommandProc){
					result = pfnCustomCommandProc(CLIBuffer+1, 0, NULL);
				}
			}else{
				LargeToSmall(CLIBuffer);		/*小文字に揃える*/
				if(p = strtok(CLIBuffer, Separators)){
					i=0;
					while(CommandTable[i].exec){
						if(!strcmp(p, CommandTable[i].command_name)) break;
						++i;
					}
					if (CommandTable[i].exec) CommandTable[i].exec(p);
					else DebugPutString("NG : Unknown command name." NEWLINE);
				}
			}
		}
	}
}

/*小文字変換*/
void LargeToSmall(char* Buffer){
	char* p;
	for(p=Buffer;p<Buffer+strlen(Buffer);p++){
		if(isupper((int)*p)){
			*p = (char)tolower((int)*p);
		}
	}
}

/*デバグポートから1行入力を待つ*/
/*コマンドはCLIBuffer[]へ格納*/
int DebugWaitCommand(void){
	BYTE c;
	int i = 0;
	while(1){
		c = DebugGetChar();
		/*CMTRACE("%02x \n", c);*/
		switch(c){
		case '\b':
			if (i>0) {
				if (EchoMode == Echo) DebugPutString("\b \b");	/*エコー*/
				--i;
			}
			break;
		case '\r':
			CLIBuffer[i++] = c;
			if (EchoMode == Echo) DebugPutChar( c );			/*エコー*/
			CLIBuffer[i] = 0x00;			/*C言語の文字列形式にする*/
			return i;
			break;
		default:
			if(i < sizeof(CLIBuffer)-1){
				CLIBuffer[i++] = c;
				if (EchoMode == Echo) DebugPutChar( c );		/*エコー*/
			}
		}
	}
}

void PrintBlank(int splen)
{
	int i;
	if(splen>0){
		for(i=0; i<splen; ++i){
			DebugPutString(" ");
		}
	}
}

/*****************************************************
コマンド処理
*****************************************************/

/*
verコマンド
format: ver
*/
void VersionCommand(char* p){
	ER ercd;
	T_RVER OS_Version;
	ercd = ref_ver(&OS_Version);
	DebugPrintf(" %s",prog_ver);
	DebugPrintf("uITRON version:" NEWLINE);
	DebugPrintf(" maker %04x,", OS_Version.maker);
	DebugPrintf(" prid %04x,", OS_Version.prid);
	DebugPrintf(" spver %04x,", OS_Version.spver);
	DebugPrintf(" prver %04x" NEWLINE, OS_Version.prver);
	DebugPutString("OK" NEWLINE);	/*verコマンド*/
}

/*
memコマンド
format: mem
*/
void MemoryCommand(char* p){
	g_MemoeyDefined = halInqTargetMemorySpec(&g_MemorySpec);
	if(g_MemoeyDefined){
		DebugPrintf("Target Memory Spec:" NEWLINE);
		DebugPrintf(" %s Addressing."	NEWLINE, (g_MemorySpec.MemCell == M_CELL8) ? "Byte" : "Word");
		DebugPrintf(" %s Endian."		NEWLINE, (g_MemorySpec.MemEndian == M_LITTLE_ENDIAN) ? "Little" : "Big");
		if(g_MemorySpec.DataBusWidth == M_UNKNOWN_DBUS){
			DebugPrintf(" Unknown Data Bus." NEWLINE);
		}else{
			DebugPrintf(" %d-Bit Data Bus." NEWLINE, g_MemorySpec.DataBusWidth*8);
		}
	}else{
		DebugPrintf("No Target Memory." NEWLINE);
	}
}


/*
modeコマンド
format mode { echo | noecho }
*/
void ModeCommand(char* p){
	p = strtok(NULL, Separators);
	if(p){
		if(!strcmp(p, "echo")){
			EchoMode = Echo;			/*echo*/
			DebugPutString("OK" NEWLINE);
		}else if(!strcmp(p, "noecho")){
			EchoMode = NoEcho;			/*no echo*/
			DebugPutString("OK" NEWLINE);
		}else{
			DebugPutString("NG : Illegal parameters." NEWLINE);
		}
	}else{
		DebugPutString("NG : No parameters." NEWLINE);
	}
}


/*
helpコマンド
format: help
*/
char command_list[] = 
		"Debug CLI Command List:" NEWLINE
		" ver" NEWLINE
		" mem" NEWLINE
		" mode { echo | noecho }" NEWLINE
		" d[{w|d}] <addr> [<count>]" NEWLINE
		" s[{w|d}] <addr> [{<op>}] <data> " NEWLINE
		"     <op> := & | ^ x X " NEWLINE
		" in{b|w|d} <port>" NEWLINE
		" out{b|w|d} <port> <data>" NEWLINE
		" int <intno>" NEWLINE
		" tsk [<tskid>]" NEWLINE
		" sem [<semid>]" NEWLINE
		" flg [<flgid>]" NEWLINE
		" mbx [<mbxid>]" NEWLINE
		" mpf [<mpfid>]" NEWLINE
//		" trc " NEWLINE
		"OK" NEWLINE;

void HelpCommand(char* p){
	DebugPutString(command_list);
}



/*
d コマンド
foramt: d <address> [<count>]
*/
const int default_size = 0x20;
void DumpByte( DWORD addr , int count );
void DumpByteCommand(char* p){
	DWORD	address, count;
	if(GetAddressParameter(p, &address)){
		p = strtok(NULL, Separators);
		if(p){
			/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
			if(!GetDwordParameter(p, &count)){
				DebugPutString("NG : Illegal <count> expression." NEWLINE);
				return;
			}
		}else{
			count = default_size;
		}
		while(1){
			char c;
			DumpByte(address, (int)count);
			DebugPrintf("continue? (exit by '.')" );
			DebugSenseChar();//受信バッファをクリア
			c = DebugGetChar();
			if(c == '.') break;
			DebugPutString(NEWLINE);
			address += count;
		}
		DebugPutString(NEWLINE "OK" NEWLINE);
	}
}

void DumpWord( DWORD addr , int count );
void DumpWordCommand(char* p)
{
	DWORD	address, count;
	if(GetAddressParameter(p, &address)){
		p = strtok(NULL, Separators);
		if(p){
			/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
			if(!GetDwordParameter(p, &count)){
				DebugPutString("NG : Illegal <count> expression." NEWLINE);
				return;
			}
		}else{
			count = default_size/2;
		}
		while(1){
			char c;
			DumpWord(address, (int)count);
			DebugPrintf("continue? (exit by '.')" );
			DebugSenseChar();//受信バッファをクリア
			c = DebugGetChar();
			if(c == '.') break;
			DebugPutString(NEWLINE);
			address += count*2;
		}
		DebugPutString(NEWLINE "OK" NEWLINE);
	}
}

void DumpDWord( DWORD addr , int count );
void DumpDWordCommand(char* p)
{
	DWORD	address, count;
	if(GetAddressParameter(p, &address)){
		p = strtok(NULL, Separators);
		if(p){
			/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
			if(!GetDwordParameter(p, &count)){
				DebugPutString("NG : Illegal <count> expression." NEWLINE);
				return;
			}
		}else{
			count = default_size/4;
		}
		while(1){
			char c;
			DumpDWord(address, (int)count);
			DebugPrintf("continue? (exit by '.')" );
			DebugSenseChar();//受信バッファをクリア
			c = DebugGetChar();
			if(c == '.') break;
			DebugPutString(NEWLINE);
			address += count*4;
		}
		DebugPutString(NEWLINE "OK" NEWLINE);
	}
}

/*
s コマンド
foramt: s <address>
*/
void WriteByteOp(DWORD addr, DWORD* data, char op)
{
	BYTE temp;
	switch(op){
	case '&':
		AND_BYTE(addr, *data);
		break;
	case '|':
		OR_BYTE(addr, *data);
		break;
	case '^':
		XOR_BYTE(addr, *data);
		break;
	case 'x':
	case 'X':
		temp = XCHG_BYTE(addr, *data);
		*data = temp;
		break;
	default:
		WRITE_BYTE(addr, *data);
		break;
	}
}
void SubstituteCommand(char* p)
{
	DWORD	start, temp;
	if(GetAddressParameter(p, &start)){
		DWORD addr = start;
		while(1){
			int count;
			BYTE byte = READ_BYTE(addr);
			char c, op = 0;
			char* p;
			if((byte >= 0x20) && (byte < 0x7f)){
				c = byte;
			}else{
				c = '.';
			}
			DebugPrintf("%08X : %02X '%c' - " , addr, byte, c);
			DebugSenseChar();//受信バッファをクリア
			count = DebugWaitCommand();
			p = strtok(CLIBuffer, Separators);
			if(p && (*p == '.')) break;
			if(p == NULL){
				++ addr;
				continue;//ENTERのみなら次のアドレスへ
			}
			//入力あり
			if(GetDwordOpParameter(p, &temp, &op)){
				//WRITE_BYTE(addr, temp);
				WriteByteOp(addr, &temp, op);
				++ addr;
			}else{
				DebugPutString("NG : Illegal <hexadecimal> expression." NEWLINE);
			}
		}
		DebugPutString("OK" NEWLINE);
	}
}



void WriteWordOp(DWORD addr, DWORD* data, char op)
{
	WORD temp;
	switch(op){
	case '&':
		AND_WORD(addr, *data);
		break;
	case '|':
		OR_WORD(addr, *data);
		break;
	case '^':
		XOR_WORD(addr, *data);
		break;
	case 'x':
	case 'X':
		temp = XCHG_WORD(addr, *data);
		*data = temp;
		break;
	default:
		WRITE_WORD(addr, *data);
		break;
	}
}
void SubstituteWordCommand(char* p)
{
	DWORD	start, temp;
	if(GetAddressParameter(p, &start)){
		DWORD addr = start;
		while(1){
			int count;
			WORD word = READ_WORD(addr);
			char op = 0;
			char* p;
			DebugPrintf("%08X : %04X - " , addr, word);
			DebugSenseChar();//受信バッファをクリア
			count = DebugWaitCommand();
			p = strtok(CLIBuffer, Separators);
			if(p && (*p == '.')) break;
			if(p == NULL){
				addr = NextAddr(addr, 2);	//addr += 2;
				continue;
			}
			if(GetDwordOpParameter(p, &temp, &op)){
				//WRITE_WORD(addr, temp);
				WriteWordOp(addr, &temp, op);
				addr = NextAddr(addr, 2);	//addr += 2;
			}else{
				DebugPutString("NG : Illegal <hexadecimal> expression." NEWLINE);
			}
		}
		DebugPutString("OK" NEWLINE);
	}
}


void WriteDWordOp(DWORD addr, DWORD* data, char op)
{
	DWORD temp;
	switch(op){
	case '&':
		AND_DWORD(addr, *data);
		break;
	case '|':
		OR_DWORD(addr, *data);
		break;
	case '^':
		XOR_DWORD(addr, *data);
		break;
	case 'x':
	case 'X':
		temp = XCHG_DWORD(addr, *data);
		*data = temp;
		break;
	default:
		WRITE_DWORD(addr, *data);
		break;
	}
}
void SubstituteDWordCommand(char* p)
{
	DWORD	start, temp;
	if(GetAddressParameter(p, &start)){
		DWORD addr = start;
		while(1){
			int count;
			DWORD dword = READ_DWORD(addr);
			char op = 0;
			char* p;
			DebugPrintf("%08X : %08X - " , addr, dword);
			DebugSenseChar();//受信バッファをクリア
			count = DebugWaitCommand();
			p = strtok(CLIBuffer, Separators);
			if(p && (*p == '.')) break;
			if(p == NULL){
				addr = NextAddr(addr, 4);	//addr += 4;
				continue;
			}
			if(GetDwordOpParameter(p, &temp, &op)){
				//WRITE_DWORD(addr, temp);
				WriteDWordOp(addr, &temp, op);
				addr = NextAddr(addr, 4);	//addr += 4;
			}else{
				DebugPutString("NG : Illegal <hexadecimal> expression." NEWLINE);
			}
		}
		DebugPutString("OK" NEWLINE);
	}
}


/*
inb コマンド
foramt: inb <address>
*/
void InbyteCommand(char* p){
	DWORD	address;
	BYTE	byte;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		DebugPutString("NG : <address> required." NEWLINE);
		return;
	}
/*	if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
	if(!GetDwordParameter(p, &tmp)){
		DebugPutString("NG : Illegal <address> expression." NEWLINE);
		return;
	}
	address = tmp;
	if(address < 0x1000000){
		byte = IN_BYTE(address);
		DebugPrintf("%08x : %02x" NEWLINE, address, byte);
		DebugPrintf("OK" NEWLINE);
	}else{
		DebugPutString("NG : Illegal address range." NEWLINE);
	}
}


/*
inw コマンド
foramt: inw <address>
*/
void InwordCommand(char* p){
	DWORD	address;
	WORD	word;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		DebugPutString("NG : <address> required." NEWLINE);
		return;
	}
	/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
	if(!GetDwordParameter(p, &tmp)){
		DebugPutString("NG : Illegal <address> expression." NEWLINE);
		return;
	}
	if (tmp & 0x01L){
		//DebugPutString("WARNING : odd address." NEWLINE);
		//return;
	}
	address = tmp;
	if(address < 0x1000000){
		word = IN_WORD(address);
		DebugPrintf("%08x : %04x" NEWLINE, address, word);
		DebugPrintf("OK" NEWLINE);
	}else{
		DebugPutString("NG : Illegal address range." NEWLINE);
	}
}


/*
ind コマンド
foramt: ind <address>
*/
void IndwordCommand(char* p){
	DWORD	address;
	DWORD	dword;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		DebugPutString("NG : <address> required." NEWLINE);
		return;
	}
	/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
	if(!GetDwordParameter(p, &tmp)){
		DebugPutString("NG : Illegal <address> expression." NEWLINE);
		return;
	}
	if (tmp & 0x01L){
		//DebugPutString("WARNING : odd address." NEWLINE);
		//return;
	}
	address = tmp;
	if(address < 0x1000000){
		dword = IN_DWORD(address);
		DebugPrintf("%08x : %08x" NEWLINE, address, dword);
		DebugPrintf("OK" NEWLINE);
	}else{
		DebugPutString("NG : Illegal address range." NEWLINE);
	}
}


/*
outb コマンド
foramt: outb <address> <byte>
*/
void OutbyteCommand(char* p){
	DWORD	address;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		DebugPutString("NG : <address> required." NEWLINE);
		return;
	}
	/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
	if(!GetDwordParameter(p, &tmp)){
		DebugPutString("NG : Illegal <address> expression." NEWLINE);
		return;
	}
	address = tmp;
	if(address < 0x1000000){
		p = strtok(NULL, Separators);
		if ( p == NULL ){
			DebugPutString("NG : <byte> required." NEWLINE);
			return;
		}
		/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
		if(!GetDwordParameter(p, &tmp)){
			DebugPutString("NG : Illegal <byte> expression." NEWLINE);
			return;
		}
		OUT_BYTE(address, tmp);
		DebugPutString("OK" NEWLINE);
	}else{
		DebugPutString("NG : Illegal address range." NEWLINE);
	}
}


/*
outw コマンド
foramt: outw <address> <word>
*/
void OutwordCommand(char* p){
	DWORD	address;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		DebugPutString("NG : <address> required." NEWLINE);
		return;
	}
	/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
	if(!GetDwordParameter(p, &tmp)){
		DebugPutString("NG : Illegal <address> expression." NEWLINE);
		return;
	}
	if (tmp & 0x01L){
		//DebugPutString("WARNING : odd address." NEWLINE);
		//return;
	}
	address = tmp;
	if(address < 0x1000000){
		p = strtok(NULL, Separators);
		if ( p == NULL ){
			DebugPutString("NG : <word> required." NEWLINE);
			return;
		}
		/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
		if(!GetDwordParameter(p, &tmp)){
			DebugPutString("NG : Illegal <word> expression." NEWLINE);
			return;
		}
		OUT_WORD(address, tmp);
		DebugPutString("OK" NEWLINE);
	}else{
		DebugPutString("NG : Illegal address range." NEWLINE);
	}
}

/*
outd コマンド
foramt: outd <address> <dword>
*/
void OutdwordCommand(char* p){
	DWORD	address;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		DebugPutString("NG : <address> required." NEWLINE);
		return;
	}
	/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
	if(!GetDwordParameter(p, &tmp)){
		DebugPutString("NG : Illegal <address> expression." NEWLINE);
		return;
	}
	if (tmp & 0x01L){
		//DebugPutString("WARNING : odd address." NEWLINE);
		//return;
	}
	address = tmp;
	if(address < 0x1000000){
		p = strtok(NULL, Separators);
		if ( p == NULL ){
			DebugPutString("NG : <dword> required." NEWLINE);
			return;
		}
		/*if(sscanf(p, "%lx%c", &tmp, &ctmp) != 1){*/
		if(!GetDwordParameter(p, &tmp)){
			DebugPutString("NG : Illegal <dword> expression." NEWLINE);
			return;
		}
		OUT_DWORD(address, tmp);
		DebugPutString("OK" NEWLINE);
	}else{
		DebugPutString("NG : Illegal address range." NEWLINE);
	}
}


/*
tsk コマンド
foramt: tsk <tskid>
*/
void TskStsCommand(char* p){
	ER		ercd;
	ID		tskid;
	T_RTSK	tskinfo;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		/*DebugPutString("NG : <tskid> required." NEWLINE);*/
		DebugPutString("Task list:" NEWLINE);
		for(tskid = MIN_OBJID; tskid < MAX_TSKID; ++tskid){
			if(ref_tsk(tskid, &tskinfo) == E_OK){
				//DebugPrintf(" %3d \"%10s\": ", tskid, GetTaskName(&tskinfo));
				PrintTaskInfo(tskid, &tskinfo);
			}
		}
		DebugPrintf("OK" NEWLINE);
	}else{
		/*if(sscanf(p, "%d%c", &itmp, &ctmp) != 1){*/
		if(!GetDwordParameter(p, &tmp)){
			DebugPutString("NG : Illegal <tskid> expression." NEWLINE);
			return;
		}
		tskid = (ID)tmp;
		ercd = ref_tsk(tskid, &tskinfo);
		if(ercd == E_OK){
			PrintTaskInfo(tskid, &tskinfo);
			DebugPrintf("OK" NEWLINE);
		}else{
			DebugPrintf("NG : Task %02x not exist." NEWLINE, tskid);
		}
	}
}

//タスク名を得る
const char* GetTaskName(T_RTSK *ptskinfo)
{
	if(ptskinfo->name == NULL) return "";
	else return ptskinfo->name;
}

void PrintID(ID id, const char *name)
{
	int namelen = strlen(name);
	int splen = 10 - namelen;
	DebugPrintf(" %02x \"%s\"", id, name);
	PrintBlank(splen);
	DebugPrintf(" :");
}

void PrintTaskInfo(ID tskid, T_RTSK *pTI)
{
	PRI tskpri = pTI->tskpri;
	UINT tskstat = pTI->tskstat;
	UINT tskwait = pTI->tskwait;
	ID	wobjid	 = pTI->wobjid;
	const char *name = GetTaskName(pTI);
	PrintID(tskid, name);
	DebugPrintf(" pri = %2d,", (int)tskpri);
	DebugPrintf(" stat =");
	if (tskstat & TTS_RUN) DebugPrintf(" RUN");
	if (tskstat & TTS_RDY) DebugPrintf(" READY");
	if (tskstat & TTS_WAI) DebugPrintf(" WAIT");
	if (tskstat & TTS_SUS) DebugPrintf(" SUSPEND");
	if (tskstat & TTS_DMT) DebugPrintf(" DORMANT");
	if (tskstat & TTS_WAI){
		if (tskwait & TTW_SLP)	DebugPrintf(" by slp_tsk");
		if (tskwait & TTW_DLY)	DebugPrintf(" by dly_tsk");
		if (tskwait & TTW_SEM)	DebugPrintf(" by wai_sem at SEM %d", wobjid);
		if (tskwait & TTW_FLG)	DebugPrintf(" by wai_flg at FLG %d", wobjid);
		if (tskwait & TTW_SDTQ) DebugPrintf(" by snd_dtq at DTQ %d", wobjid);
		if (tskwait & TTW_RDTQ) DebugPrintf(" by rcv_dtq at DTQ %d", wobjid);
		if (tskwait & TTW_MBX)	DebugPrintf(" by rcv_mbx at MBX %d", wobjid);
		if (tskwait & TTW_MTX)	DebugPrintf(" by loc_mtx at MTX %d", wobjid);
		if (tskwait & TTW_SMBF) DebugPrintf(" by snd_mbf at MBF %d", wobjid);
		if (tskwait & TTW_RMBF) DebugPrintf(" by rcv_mbf at MBF %d", wobjid);
		if (tskwait & TTW_CAL)	DebugPrintf(" by cal_por at POR %d", wobjid);
		if (tskwait & TTW_ACP)	DebugPrintf(" by acp_por at POR %d", wobjid);
		if (tskwait & TTW_RDV)	DebugPrintf(" wait for rendez-vous completion");
		if (tskwait & TTW_MPF)	DebugPrintf(" by get_mpf at MPF %d", wobjid);
		if (tskwait & TTW_MPL)	DebugPrintf(" by get_mpl at MPL %d", wobjid);
		DebugPrintf(", lefttmo = %d", pTI->lefttmo);
	}
	DebugPrintf("" NEWLINE);
}

/*
sem コマンド
foramt: sem <semid>
*/
void PrintSemaphoreInfo(ID semid, T_RSEM	*p_seminfo);
void SemStsCommand(char* p){
	ER		ercd;
	ID		semid;
	T_RSEM	seminfo;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		/*DebugPutString("NG : <semid> required." NEWLINE);*/
		DebugPutString("Semaphore list:" NEWLINE);
		for(semid = MIN_OBJID; semid < MAX_SEMID; ++semid){
			if(ref_sem(semid, &seminfo) == E_OK){
				PrintSemaphoreInfo(semid, &seminfo);
			}
		}
		DebugPrintf("OK" NEWLINE);
	}else{
		/*if(sscanf(p, "%d%c", &itmp, &ctmp) != 1){*/
		if(!GetDwordParameter(p, &tmp)){
			DebugPutString("NG : Illegal <semid> expression." NEWLINE);
			return;
		}
		semid = (ID)tmp;
		ercd = ref_sem(semid, &seminfo);
		if(ercd == E_OK){
			PrintSemaphoreInfo(semid, &seminfo);
			DebugPrintf("OK" NEWLINE);
		}else{
			DebugPrintf("NG : Semaphore %02x not exist." NEWLINE, semid);
		}
	}
}

//セマフォ名を得る
const char* GetSemaphoreName(T_RSEM *pseminfo)
{
	if(pseminfo->name == NULL) return "";
	else return pseminfo->name;
}

void PrintSemaphoreInfo(ID semid, T_RSEM *pSI)
{
	const char *name = GetSemaphoreName(pSI);
	PrintID(semid, name);
	DebugPrintf(" semcnt = %04xH. ", pSI->semcnt);
	if(pSI->wtskid == TSK_NONE)
		DebugPrintf("No tasks are waiting.");
	else
		DebugPrintf("Task %02x is waiting.", pSI->wtskid);
	DebugPrintf("" NEWLINE);
}

/*
flg コマンド
foramt: flg <flgid>
*/
void PrintEventflagInfo(ID flgid, T_RFLG	*p_flginfo);
void FlgStsCommand(char* p){
	ER		ercd;
	ID		flgid;
	T_RFLG	flginfo;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		/*DebugPutString("NG : <flgid> required." NEWLINE);*/
		DebugPutString("Eventflag list:" NEWLINE);
		for(flgid = MIN_OBJID; flgid < MAX_FLGID; ++flgid){
			if(ref_flg(flgid, &flginfo) == E_OK){
				PrintEventflagInfo(flgid, &flginfo);
			}
		}
		DebugPrintf("OK" NEWLINE);
	}else{
		/*if(sscanf(p, "%d%c", &itmp, &ctmp) != 1){*/
		if(!GetDwordParameter(p, &tmp)){
			DebugPutString("NG : Illegal <flgid> expression." NEWLINE);
			return;
		}
		flgid = (ID)tmp;
		ercd = ref_flg(flgid, &flginfo);
		if(ercd == E_OK){
			PrintEventflagInfo(flgid, &flginfo);
			DebugPrintf("OK" NEWLINE);
		}else{
			DebugPrintf("NG : Eventflag %02x not exist." NEWLINE, flgid);
		}
	}
}

//イベントフラグ名を得る
const char* GetEventflagName(T_RFLG *pflginfo)
{
	if(pflginfo->name == NULL) return "";
	else return pflginfo->name;
}

void PrintEventflagInfo(ID flgid, T_RFLG	*pFI)
{
	const char *name = GetEventflagName(pFI);
	PrintID(flgid, name);
	DebugPrintf(" flgptn = %04xH. ", pFI->flgptn);
	if(pFI->wtskid == TSK_NONE)
		DebugPrintf("No tasks are waiting.");
	else
		DebugPrintf("Task %02x is waiting.", pFI->wtskid);
	DebugPrintf("" NEWLINE);
}

/*
mbx コマンド
foramt: mbx <mbxid>
*/
void PrintMailboxInfo(ID mbxid, T_RMBX	*p_mbxinfo);
void MbxStsCommand(char* p){
	ER		ercd;
	ID		mbxid;
	T_RMBX	mbxinfo;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		/*DebugPutString("NG : <mbxid> required." NEWLINE);*/
		DebugPutString("Mailbox list:" NEWLINE);
		for(mbxid = MIN_OBJID; mbxid < MAX_MBXID; ++mbxid){
			if(ref_mbx(mbxid, &mbxinfo) == E_OK){
				PrintMailboxInfo(mbxid, &mbxinfo);
			}
		}
		DebugPrintf("OK" NEWLINE);
	}else{
		/*if(sscanf(p, "%d%c", &itmp, &ctmp) != 1){*/
		if(!GetDwordParameter(p, &tmp)){
			DebugPutString("NG : Illegal <mbxid> expression." NEWLINE);
			return;
		}
		mbxid = (ID)tmp;
		ercd = ref_mbx(mbxid, &mbxinfo);
		if(ercd == E_OK){
			PrintMailboxInfo(mbxid, &mbxinfo);
		}else{
			DebugPrintf("NG : Mailbox %02x not exist." NEWLINE, mbxid);
		}
	}
}

//メイルボックス名を得る
const char* GetMailboxName(T_RMBX *pmbxinfo)
{
	if(pmbxinfo->name == NULL) return "";
	else return pmbxinfo->name;
}

void PrintMailboxInfo(ID mbxid, T_RMBX	*pMI)
{
	const char *name = GetMailboxName(pMI);
	PrintID(mbxid, name);
	if(pMI->wtskid == TSK_NONE)
		DebugPrintf(" No tasks are waiting.");
	else
		DebugPrintf(" Task %02x is waiting.", pMI->wtskid);
	if(pMI->pk_msg)
		DebugPrintf(" %d messages(%08lxh ...) exist." NEWLINE, pMI->msgcnt, (DWORD)pMI->pk_msg);
	else
		DebugPrintf(" No messages exist." NEWLINE);
}

/*
mpf コマンド
foramt: mpf <mpfid>
*/
void PrintFixedMemoryPoolInfo(ID mpfid, T_RMPF	*pMI);
void MpfStsCommand(char* p){
	ER		ercd;
	ID		mpfid;
	T_RMPF	mpfinfo;
	DWORD	tmp;
	/*char	ctmp;*/
	p = strtok(NULL, Separators);
	if ( p == NULL ){
		/*DebugPutString("NG : <semid> required." NEWLINE);*/
		DebugPutString("Memory pool list:" NEWLINE);
		for(mpfid = MIN_OBJID; mpfid < MAX_MPFID; ++mpfid){
			if(ref_mpf(mpfid, &mpfinfo) == E_OK){
				PrintFixedMemoryPoolInfo(mpfid, &mpfinfo);
			}
		}
		DebugPrintf("OK" NEWLINE);
	}else{
		/*if(sscanf(p, "%d%c", &itmp, &ctmp) != 1){*/
		if(!GetDwordParameter(p, &tmp)){
			DebugPutString("NG : Illegal <semid> expression." NEWLINE);
			return;
		}
		mpfid = (ID)tmp;
		ercd = ref_mpf(mpfid, &mpfinfo);
		if(ercd == E_OK){
			PrintFixedMemoryPoolInfo(mpfid, &mpfinfo);
		}else{
			DebugPrintf("NG : Memory Pool %02x not exist." NEWLINE, mpfid);
		}
	}
}

//メモリプール名を得る
const char* GetFixedMemoryPoolName(T_RMPF *pmpfinfo)
{
	if(pmpfinfo->name == NULL) return "";
	else return pmpfinfo->name;
}

void PrintFixedMemoryPoolInfo(ID mpfid, T_RMPF	*pMI)
{
	const char *name = GetFixedMemoryPoolName(pMI);
	PrintID(mpfid, name);
	DebugPrintf(" blkcnt=%d blksz=%d. %d free blocks.",
		pMI->blkcnt, pMI->blksz, pMI->fblkcnt);
	if(pMI->wtskid == TSK_NONE)
		DebugPrintf(" No tasks are waiting." NEWLINE);
	else
		DebugPrintf(" Task %02x is waiting." NEWLINE, pMI->wtskid);
}


#if 0
/*
trcコマンド
format: trc
*/
void PrintTraceEntry(T_TRCENT *pEntry);
void GetTraceCommand(char* p)
{
	T_TRCENT *pEntry;
	T_TRCENT *pTop = _TraceBuf.tr_trbtop;
	T_TRCENT *pTail = _TraceBuf.tr_trbbtm;
	T_TRCENT *pNext = _TraceBuf.tr_trbins;

	DebugPrintf("Trace Info:" NEWLINE);
	DebugPrintf(" time      attr  tsk f/e  r1   er2      r3   r4   pc   ccr" NEWLINE);
	pEntry = pNext;
	while(pEntry<pTail){
		PrintTraceEntry(pEntry);
		++ pEntry;
	}
	pEntry = pTop;
	while(pEntry<pNext){
		PrintTraceEntry(pEntry);
		++ pEntry;
	}
	DebugPutString("OK" NEWLINE);
}

void PrintTraceEntry(T_TRCENT *pEntry)
{
	switch(pEntry->te_attr){
	case 0x0001:/*SVC*/
		DebugPrintf(" %08lx:", pEntry->te_ltime);
		DebugPrintf(" SVC  ");
		DebugPrintf(" %3d", pEntry->te_tskid);
		DebugPrintf(" %04x", pEntry->te_event);
		DebugPrintf(" %04x", pEntry->te_r1);
		DebugPrintf(" %08x", pEntry->te_er2);
		DebugPrintf(" %04x", pEntry->te_r3);
		DebugPrintf(" %04x", pEntry->te_r4);
		DebugPrintf(" %04x", pEntry->te_ccr_pc);
		DebugPrintf(" %04x", pEntry->te_pc);
		break;
	case 0x0002:/*RTN*/
		DebugPrintf(" %08lx:", pEntry->te_ltime);
		DebugPrintf(" RTN  ");
		DebugPrintf(" %3d", pEntry->te_tskid);
		DebugPrintf(" %04x", pEntry->te_event);
		DebugPrintf(" %04x", pEntry->te_r1);
		DebugPrintf(" %08x", pEntry->te_er2);
		DebugPrintf(" %04x", pEntry->te_r3);
		DebugPrintf(" %04x", pEntry->te_r4);
		DebugPrintf(" %04x", pEntry->te_ccr_pc);
		DebugPrintf(" %04x", pEntry->te_pc);
		break;
	case 0x0003:/*CONT*/
		DebugPrintf(" %08lx:", pEntry->te_ltime);
		DebugPrintf(" CONT ");
		DebugPrintf(" %3d", pEntry->te_tskid);
		break;
	case 0x0004:/*IDLE*/
		DebugPrintf(" %08lx:", pEntry->te_ltime);
		DebugPrintf(" IDLE ");
		break;
	default:
		DebugPrintf(" %08lx:", pEntry->te_ltime);
		DebugPrintf(" ???? ");
		break;
	}
	DebugPrintf("" NEWLINE);
}

#endif



/*パラメータ取り出し*/
BOOL GetDwordOpParameter(char *s, DWORD *pDword, char* op)
{
	switch(*s){
	case '&':
	case '|':
	case '^':
	case 'x':
	case 'X':
		*op = *s++;
		break;
	}
	return GetDwordParameter(s, pDword);
}

/*パラメータ取り出し*/
BOOL GetDwordParameter(char *s, DWORD *pDword)
{
	char c;
	*pDword = 0x0;
	while(*s){
		c = toupper(*s);
		if(isxdigit(c)){
			c -= c >= 'A' ? ('A'-10) : '0';
			*pDword <<= 4;
			*pDword |= (DWORD)c;
		}else return FALSE;//16進文字列でない
		++s;
	}
	return TRUE;
}

/*<address>*/
BOOL GetAddressParameter(char *s, DWORD *pAddr)
{
	DWORD	tmp;
	char* p = strtok(NULL, Separators);
	if ( p == NULL ){
		DebugPutString("NG : <address> required." NEWLINE);
		return FALSE;
	}
	if(!GetDwordParameter(p, &tmp)){
		DebugPutString("NG : Illegal <address> expression." NEWLINE);
		return FALSE;
	}
	if(tmp < 0x1000000){
		*pAddr = tmp;
		return TRUE;
	}else{
		DebugPutString("NG : Illegal address range." NEWLINE);
		return FALSE;
	}
}

/*表示関数*/
void DumpByte( DWORD addr , int count )
{
	int   lc;
	int    i, ct, offset, lmax;
	BYTE   ascii[0x20];
	DWORD  base, start, last, cur;
	BYTE   ch;

	base  = addr;
	last  = addr + count;
    start = addr;			/*行表示開始位置*/
    cur	  = addr;			/*表示位置*/
	/*16バイトを１行として表示*/
    while( cur < last ){
        if ( (cur == addr) || (( cur & 0x00ff ) == 0x00) ){
	    	if ( cur > base)
				DebugPrintf(NEWLINE);/*100hバイト表示ごとに１行開ける*/
            DebugPrintf("           00 01 02 03 04 05 06 07 - 08 09 0a 0b 0c 0d 0e 0f " NEWLINE);
            DebugPrintf("           ------------------------------------------------- " NEWLINE);
        }
        DebugPrintf("%08x   " , cur & (~0xf));/*アドレス*/ 
		for( i = 0; i < 0x20 ; i++ ) ascii[i] = 0;   /* バッファクリア */
		offset = cur & 0xf;
		if(cur == base){
			if(offset > 0){
				for(i = 0; i<offset; ++i){
					if( i == 8 ) DebugPrintf( "  " );
					DebugPrintf("   ");
				}
			}
		}
		lmax = 16 - offset;
        for( lc = 0  ,ct = 0 ; lc < lmax ; lc++ ){
			offset = cur & 0xf;
            if( cur < last ){
                if( offset == 8 ) DebugPrintf( "- " );
				ch = READ_BYTE(start+lc);
                DebugPrintf("%02x ", ch );
				if( ( ch >= 0x20 ) && ( ch < 0x80 ) ) ascii[ct] = ch;
				else                                  ascii[ct] = '.';
                ct++;
				cur++;
            }else{
                if( (lc) == 8 ) DebugPrintf( "  " );
                DebugPrintf("   ");
            }
        }
        DebugPrintf( "'" );
        DebugPrintf( "%s", ascii );
        DebugPrintf("'" NEWLINE);
		start = cur;/*表示開始位置*/
    }
    DebugPrintf(NEWLINE);
}

void DumpWord( DWORD addr , int count )
{
	int i,j;
	for(i=0; i<count; ){
		DebugPrintf("%08x : ", addr);
		for(j=0; j<8; ++j){
			DebugPrintf("%04x  ", READ_WORD(addr));
			addr = NextAddr(addr, 2);	//addr += 2;
			if(++i == count) break;
		}
		DebugPrintf(NEWLINE);
	}
}

void DumpDWord( DWORD addr , int count )
{
	int i,j;
	for(i=0; i<count; ){
		DebugPrintf("%08x : ", addr);
		for(j=0; j<4; ++j){
			DebugPrintf("%08x  ", READ_DWORD(addr));
			addr = NextAddr(addr, 4);	//addr += 4;
			if(++i == count) break;
		}
		DebugPrintf(NEWLINE);
	}
}

/*****************************************************
異常終了処理
*****************************************************/
#if 0
void Abort(ABORTINFO *pInfo)
{
	DebugPrintf("Abort: vecno=%02xH, tskid=%02xH, ercd=%04xH" NEWLINE,
					pInfo->vecno,
					pInfo->tskid,
					pInfo->ercd
	);
}

void IllegalInt(ILLINTINFO *pInfo)
{
	DebugPrintf("IllegalInterrupt: vecno=%02xH, tskid=%02xH, ccr=%02xH, pc=%06xlH" NEWLINE,
					pInfo->vecno,
					pInfo->tskid,
					(BYTE)(pInfo->pc >> 24),
					pInfo->pc & 0x00ffffff
	);
}
#endif



/*****************************************************
デバグポートの入出力処理
デバグコンソール制御
*****************************************************/

/*コンソール入出力要求メッセージの共通部*/
typedef struct tagConsoleMessageHeader{
	T_MSG		os_rsv;			/*OS管理領域*/
	BYTE		func;			/*ファンクションコード*/
	BYTE		mbxid;			/*メイルボックスID	*/
}CONMSGHEADER;/*6 bytes*/

/*出力メッセージ形式*/
typedef struct tagConsoleOutMessage{
	CONMSGHEADER	header;
	BYTE			data[256];
}COMSG;

/*入力メッセージ形式*/
typedef struct tagConsoleInMessage{
	CONMSGHEADER	header;
	BYTE			data;
	BYTE			status;
}CIMSG;

int DebugPort = DP_NONE;
struct st_sci *pSCI;
COMSG	CoMsg;
CIMSG	CiMsg;



/*デバグコンソールの初期化*/
void DebugInitConsole(int port)
{
	if(port < 2){
		DebugPort = port;
		if (port == 1) {
			halSerialInit(0);
		}
	}
}

/*デバグコンソールへ１文字出力*/
void DebugPutChar(char c)
{
	if (DebugPort > 0){
		halSerialWriteChar(0, c);
	}
}

/*デバグコンソールから１文字入力を待つ*/
char DebugGetChar(void)
{
	int c = -1;
	if (DebugPort > 0){
		while((c = halSerialReadChar(0)) < 0){
			dly_tsk(10);/*2023,2,27追加*/
		}
	}
	return c;
}

/*デバグコンソールを入力をセンス*/
WORD DebugSenseChar(void)
{
	return halSerialReadChar(0);
}

/*デバグポートへ文字列を表示する*/
void DebugPutString(char* s){
	if (DebugPort > 0){
		while(*s)
			halSerialWriteChar(0, *s++);
	}
}

/*デバグポートへ書式付き文字列を表示する*/
void DebugPrintf(const char *formatstring, ...)
{
	static char s[1024];
	va_list argp;
	va_start(argp, formatstring);
	vsprintf(s, formatstring, argp);
	va_end(argp);
	DebugPutString(s);
}

#if 0
/*メッセージの内容をダンプ*/
void DebugDumpMessage(MSGBLOCK* pMsg)
{
	int i;
	DebugPrintf("(%02x %02x %04x) : ",
				(BYTE)pMsg->mheader.id,
				(BYTE)pMsg->mheader.sub,
				pMsg->mheader.length);
	for(i=0;i<pMsg->mheader.length;i++){
		DebugPrintf("%02x ",pMsg->data[i]);
	}
	DebugPutChar('\r');
}

#endif