#include "version.h"
#include "emucomm.h"
#include "emullfw.h"
#include "emudebug.h"
#include <string.h>

U8  *bin2hex;
U16 previous_cmd;

#define SIM_READ  0
#define SIM_WRITE 1

void sh_sim(U16 cmd)
{ U16 reg_num,reg_len,i;
  U32 reg_data;
  U8  *s,Ch,status;
  TransmitByte('S');
  TransmitByte('I');
  TransmitByte('M');
  TransmitByte(':');
  if((s=GetStr(1))==0)
    return;
  TransmitByte('B');
  TransmitByte('/');
  TransmitByte('L');
  TransmitByte('/');
  TransmitByte('D');
  for(reg_len=0;!reg_len;)
  {
    for(;;)
    {
      SetDmaCount(1);
      if(Ch=ReceiveByte())
        break;
    }
    if(Ch==27)
      reg_len=0xFF;
    else if((Ch=='l')||(Ch=='L'))
      reg_len=4;
    else if((Ch=='b')||(Ch=='B'))
      reg_len=1;
    else if((Ch=='d')||(Ch=='D'))
      reg_len=2;
    else
      TransmitByte(7);
  }
  TransmitByte(13);
  if(reg_len==0xFF)
    return;
  previous_cmd=cmd;
  if(hex2word(s,(U8*)&reg_num))
  { SendHexErr();
    return; }
  if(reg_len==2)
    status=OvpRegister(reg_num,SIM_READ,reg_len,&reg_data,0x148);
  else
    status=IntRegister(reg_num,SIM_READ,reg_len,&reg_data,0);
  HexByteStr(0,&status);
  HexByteStr(',',&exceptBreak);
  HexByteStr(',',(U8*)&reg_data);
  for(i=1; i<reg_len; i++)
    HexByteStr(0,((U8*)&reg_data)+i);
  if(status)
  {
    TransmitByte(13);
    TransmitByte(10);
    return;
  }
  TransmitByte(' ');
  TransmitByte('-');
  TransmitByte('>');
  if((s=GetStr(1))==0)
    return;
  if(reg_len==1)
  {
    if(hex2bin(s,(U8*)&reg_data))
    { SendHexErr();
      return; }
  }
  else if(hex2meml(s,(U8*)&reg_data))
  { SendHexErr();
    return; }
  if(reg_len==2)
    status=OvpRegister(reg_num,SIM_WRITE,reg_len,&reg_data,0x148);
  else
    status=IntRegister(reg_num,SIM_WRITE,reg_len,&reg_data,0);
  HexByteStr(0,&status);
  HexByteStr(',',&exceptBreak);
  TransmitByte(13);
  TransmitByte(10);
}

void show_sys_reg(U8 *buff)
{
  TransmitByte(' ');
  TransmitByte('S');
  TransmitByte('P');
  HexLongStr(':',buff);
  TransmitByte(' ');

  TransmitByte('P');
  TransmitByte('C');
  HexLongStr(':',buff+1*4);
  TransmitByte(13);
  TransmitByte(10);
}

void sh_go(U16 cmd)
{ U8 status;
  TransmitByte('G');
  TransmitByte(':');
  exceptBreak=0;
  status=GoEP();
  HexByteStr(0,&status);
  HexByteStr(',',&exceptBreak);
  TransmitByte(13);
  TransmitByte(10);
  previous_cmd=cmd;
}

void sh_poll(U16 cmd)
{ U32 buff[2];
  U8 status;
  TransmitByte('P');
  TransmitByte(':');
  exceptBreak=0;
  status=EPstatus(buff);
  HexByteStr(0,&status);
  HexByteStr(',',&exceptBreak);
  show_sys_reg((U8*)buff);
  previous_cmd=cmd;
}

void sh_step(U16 cmd)
{ U32 buff[2];
  U8 status;
  TransmitByte('S');
  TransmitByte(':');
  exceptBreak=0;
  status=InstructionStep(buff);
  HexByteStr(0,&status);
  HexByteStr(',',&exceptBreak);
  show_sys_reg((U8*)buff);
  previous_cmd=cmd;
}

void sh_halt()
{ U32 buff[2];
  U8 status;
  TransmitByte('H');
  TransmitByte(':');
  exceptBreak=0;
  status=StopEP(buff);
  HexByteStr(0,&status);
  HexByteStr(',',&exceptBreak);
  show_sys_reg((U8*)buff);
}

void sh_trig_msg(U8);
void sh_trig_level()
{ U16 Bit,arg[2];
  U8 Ch;
  arg[0]=arg[1]=BP_NONE;
  sh_trig_msg(0);
  for(;;)
  {
    SetDmaCount(1);
    Ch=ReceiveByte();
    if(('0'<=Ch)&&(Ch<='9'))
      Bit=1<<(Ch-'0');
    else if(('A'<=Ch)&&(Ch<='C'))
      Bit=1<<(Ch-'A'+10);
    else if(('a'<=Ch)&&(Ch<='c'))
      Bit=1<<(Ch-'a'+10);
    else if(Ch==13)
      break;
    else if(Ch==27)
    {
      TransmitByte(13);
      TransmitByte('A');
      TransmitByte('b');
      TransmitByte('o');
      TransmitByte('r');
      TransmitByte('t');
      TransmitByte(13);
      TransmitByte(10);
      return;
    }
    else
      continue;
    arg[0]^=Bit;
    HexLongStr(13,(U8*)arg);
  }
  sh_trig_msg(1);
  if(arg[0]==0)
  {
    SetTriggerLevel(BP_NONE,BP_NONE);
    TransmitByte(13);
    TransmitByte(10);
    return;
  }
  for(;;)
  {
    SetDmaCount(1);
    Ch=ReceiveByte();
    if(('0'<=Ch)&&(Ch<='9'))
      Bit=1<<(Ch-'0');
    else if(('A'<=Ch)&&(Ch<='C'))
      Bit=1<<(Ch-'A'+10);
    else if(('a'<=Ch)&&(Ch<='c'))
      Bit=1<<(Ch-'a'+10);
    else if(Ch==13)
      break;
    else if(Ch==27)
    {
      TransmitByte(13);
      TransmitByte('A');
      TransmitByte('b');
      TransmitByte('o');
      TransmitByte('r');
      TransmitByte('t');
      TransmitByte(13);
      TransmitByte(10);
      return;
    }
    else
      continue;
    arg[1]^=Bit;
  }
  SetTriggerLevel(arg[0],arg[1]);
  TransmitByte(13);
  TransmitByte(10);
}

void sh_trig(U16 cmd)
{ U8 Ch,*s;
  U32 arg[2];
  for(;;)
  {
    SetDmaCount(1);
    if((Ch=ReceiveByte())>='a')
      Ch-=('a'-'A');
    switch(Ch)
    {
      case 27:
        TransmitByte('\\');
        TransmitByte(13);
        TransmitByte(10);
        return;
      case 'D':
      case 'P':
        previous_cmd=cmd;
        TransmitByte(Ch);
        TransmitByte(13);
        TransmitByte(10);
        for(;;)
        {
          TransmitByte(Ch);
          TransmitByte('B');
          TransmitByte('R');
          TransmitByte(':');
          if((s=GetStr(1))==0)
            return;
          if(hex2long(s,(U8*)arg))
            SendHexErr();
          else
            break;
        }
        for(;;)
        {
          TransmitByte(Ch);
          TransmitByte('B');
          TransmitByte('M');
          TransmitByte('R');
          TransmitByte(':');
          if((s=GetStr(1))==0)
            return;
          if(hex2long(s,(U8*)(arg+1)))
            SendHexErr();
          else
            break;
        }
        SetBreakPoint((Ch=='P')?BP_PC:BP_DLong,arg);
        return;
      case 'A':
        previous_cmd=cmd;
        TransmitByte('A');
        TransmitByte(13);
        TransmitByte(10);
        for(;;)
        {
          TransmitByte('A');
          TransmitByte('B');
          TransmitByte('L');
          TransmitByte('R');
          TransmitByte(':');
          if((s=GetStr(1))==0)
            return;
          if(hex2long(s,(U8*)arg))
            SendHexErr();
          else
            break;
        }
        for(;;)
        {
          TransmitByte('A');
          TransmitByte('B');
          TransmitByte('H');
          TransmitByte('R');
          TransmitByte(':');
          if((s=GetStr(1))==0)
          {
            SetBreakPoint(BP_SAddr,arg);
            return;
          }
          if(hex2long(s,(U8*)(arg+1)))
            SendHexErr();
          else
            break;
        }
        SetBreakPoint(BP_RAddr,arg);
        return;
      case 'B':
        previous_cmd=cmd;
        TransmitByte('B');
        TransmitByte(13);
        TransmitByte(10);
        for(;;)
        {
          TransmitByte('A');
          TransmitByte('A');
          TransmitByte('B');
          TransmitByte('R');
          TransmitByte(':');
          if((s=GetStr(1))==0)
            return;
          if(hex2word(s,(U8*)arg))
            SendHexErr();
          else
            break;
        }
        SetBreakPoint(BP_Attrib,arg);
        return;
      case 'L':
        previous_cmd=cmd;
        TransmitByte('L');
        TransmitByte(13);
        TransmitByte(10);
        sh_trig_level();
        return;
      default:
        if(timeOut==0)
          TransmitByte(7);
    }
  }
}

extern U32 Trace_PC[2];
void sh_trace(U16 cmd)
{ U8 Ch,buff[8];
  for(;;)
  {
    SetDmaCount(1);
    switch(Ch=ReceiveByte())
    {
      case 27:
        TransmitByte('\\');
        TransmitByte(13);
        TransmitByte(10);
        return;
      case '0':
        TransmitByte('0');
        TraceReset();
        TransmitByte(13);
        TransmitByte(10);
        previous_cmd=cmd;
        return;
      case '1':
        TransmitByte('1');
        TraceDisable();
        TransmitByte(13);
        TransmitByte(10);
        previous_cmd=cmd;
        return;
      case '2':
      case '3':
        TransmitByte(Ch);
        TraceEnable((U8)(Ch-'2'));
        TransmitByte(13);
        TransmitByte(10);
        previous_cmd=cmd;
        return;
      case '4':
        TransmitByte('4');
        TransmitByte(13);
        TransmitByte(10);
        TraceStatus((U16*)buff);
        HexByteStr(0,buff+1);
        HexByteStr(0,buff+0);
        HexLongStr(':',(U8*)Trace_PC);
        HexByteStr(',',buff+3);
        HexByteStr(0,buff+2);
        if(*(U16*)(buff+4))
        {
          HexByteStr(',',buff+5);
          HexByteStr(0,buff+4);
          HexLongStr(':',(U8*)(Trace_PC+1));
        }
        TransmitByte(13);
        TransmitByte(10);
        previous_cmd=cmd;
        return;
      default:
        if(timeOut==0)
          TransmitByte(7);
    }
  }
}

void sh_rst(U16 cmd)
{ U32 buff[2];
  U8 status;
  TransmitByte('R');
  TransmitByte(':');
  exceptBreak=0;
  status=Reset(buff);
  HexByteStr(0,&status);
  HexByteStr(',',&exceptBreak);
  show_sys_reg((U8*)buff);
  previous_cmd=cmd;
}

void sh_repeat()
{
  if(previous_cmd)
    Shell_func(previous_cmd);
}

void sh_err()
{
  TransmitByte('?');
  TransmitByte(7);
  TransmitByte(13);
  TransmitByte(10);
}

void Shell_Cmd(U8 *Cmd_Table[],U8 *Cmd)
{ U16 i;
  for(i=1;Cmd_Table[i];i++)
    if(strcmp(Cmd_Table[i],Cmd)==0)
    {
      Shell_func(i);
      return;
    }
  Shell_func(0);
}


void Shell(U8 *Cmd_Table[])
{ U8 *Cmd;
  U8 HexStr[]={'0','1','2','3','4','5','6','7',
               '8','9','A','B','C','D','E','F'};
  bin2hex=HexStr;
  previous_cmd=0;
  for(;;)
  {
    TransmitByte('%');
    if(Cmd=GetStr(1))
      Shell_Cmd(Cmd_Table,Cmd);
  }
}

/*void Shell(U16 R_SP,U16 R_BP)
{ TransmitByte('S');
  TransmitByte('P');
  HexWordStr('=',(U8*)&R_SP);
  TransmitByte(',');
  TransmitByte('B');
  TransmitByte('P');
  HexWordStr('=',(U8*)&R_BP);
  TransmitByte(13);
  TransmitByte(10);
  SetWatchDog(17);
  for(timeOut=0;timeOut==0;);
}*/

void TestPST()
{ int prePST = -1;
  int cntPST = 0;
  int PST;
  do{
    SetDmaCount(1);
    if((PST=GetPST()) != prePST)
    {
      if(cntPST)
        HexByteStr('+',(U8*)&cntPST);
      TransmitByte(13);
      TransmitByte(10);
      TransmitByte(bin2hex[PST]);
      cntPST=0;
      prePST=PST;
    }
    else if(++cntPST >= 255)
    {
      HexByteStr('+',(U8*)&cntPST);
      cntPST= 0;
      prePST= -1;
    }
  }while(ReceiveByte() != ' ');
  if(cntPST)
    HexByteStr('+',(U8*)&cntPST);
  TransmitByte(13);
  TransmitByte(10);
}

void SendTitle(void)
{ U8 DBUG_TITLE[]={13,10,'W','e','l','c','o','m','e',' ',
                   't','o',' ','M','I','C','E',' ',
                   'D','e','b','u','g',' ','S','y','s','t','e','m',13,10,
                   'M','I','C','R','O','T','E','K',' ',
                   'I','n','t','e','r','n','a','t','i','o','n','a','l',' ',
                   'I','n','c','.',0};
  PutStr(DBUG_TITLE);
}

void SendDigit(U16 t)
{ U8 s[8];
  int i;
  s[0]=bin2hex[t%10];
  s[1]='.';
  s[2]=bin2hex[(t/=10)%10];
  for(i=3;t/=10;i++)
    s[i]=bin2hex[t%10];
  while(i)
    TransmitByte(s[--i]);
}

void SendTime(U16 t)
{
  TransmitByte('W');
  TransmitByte('/');
  TransmitByte('R');
  TransmitByte('/');
  TransmitByte('W');
  TransmitByte('/');
  TransmitByte('R');
  TransmitByte(' ');
  TransmitByte('6');
  TransmitByte('4');
  TransmitByte('K');
  TransmitByte(' ');
  TransmitByte('B');
  TransmitByte('y');
  TransmitByte('t');
  TransmitByte('e');
  TransmitByte(' ');
  TransmitByte('i');
  TransmitByte('n');
  TransmitByte(' ');
  SendDigit((t+1) >> 1);
  TransmitByte('s');
  TransmitByte('e');
  TransmitByte('c');
  TransmitByte(' ');
  TransmitByte('(');
  SendDigit(3000/t);
  TransmitByte('M');
  TransmitByte('B');
  TransmitByte('/');
  TransmitByte('m');
  TransmitByte(')');
  TransmitByte(13);
  TransmitByte(10);
}

void TestCmd(U8 *Cmd)
{ char Str0[]={'R','S','T','H',0};
  char Str1[]={'R','S','T','L',0};
  char Str2[]={'T','E','A','H',0};
  char Str3[]={'T','E','A','L',0};
  char Str4[]={'B','K','P','H',0};
  char Str5[]={'B','K','P','L',0};
  char *CmdStr[]={Str0,Str1,Str2,Str3,Str4,Str5,0};

#if (_VERSION_ == 0) || (_VERSION_ == 2)
  U16  CmdWord[]={0xFF80,0x7F00, 0xFF40,0xBF00, 0xFF01,0xFE00};
#endif
#if _VERSION_ == 1
  U16  CmdWord[]={0xFF80,0x7F00, 0xFF02,0xFD00, 0xFF01,0xFE00};
#endif

  char StrTBDM[]={'T','B','D','M',0};
  char StrTRST[]={'T','R','S','T',0};
  char StrDRST[]={'D','R','S','T',0};
  char StrTBUF[]={'T','B','U','F',0};
  char StrDBUF[]={'D','B','U','F',0};
  char StrRST[]={'R','E','S','E','T',0};
  char StrREG[]={'R','E','G',0};
  char StrCMPB[]={'C','M','P','B',0};
  char StrCMPW[]={'C','M','P','W',0};
  char StrCPYp[]={'C','P','Y','+',0};
  char StrCPYm[]={'C','P','Y','-',0};
  char StrSearch[]={'S','E','A','R','C','H',0};
  char BDMerr[]={'B','D','M','e','r','r',0};
  char FillOK[]={'F','i','l','l',' ','C','o','m','p','l','e','t','e',0};
  char TestOK[]={'T','e','s','t',' ','C','o','m','p','l','e','t','e',0};
  char CmdAbort[]={'A','B','O','R','T',0};
  char StrEPBK[]={'E','P','B','K',0};
  char StrPST[]={'P','S','T',0};
  char StrDSH[]={'D','S','H',0};
  char StrKEY[]={'K','E','Y',0};
  char StrVER[]={'V','E','R',0};
  char StrPWM[]={'P','W','M',0};

  U8 MemBuff[128],*str;

  U8 h,l;
  U32 BDMbuf;
  U16 delta;
  int i;

  for(l=0;CmdStr[l];l++)
    if(strcmp(Cmd,CmdStr[l])==0)
#if (_VERSION_ == 0) || (_VERSION_ == 2)
      if((l==4)||(l==5))
      { TestEP(CmdWord[l]);
        return; }
      else
      { TestP2(CmdWord[l]);
        return; }
#endif
#if _VERSION_ == 1
      if((l==0)||(l==1))
      { TestP2(CmdWord[l]);
        return; }
      else
      { TestEP(CmdWord[l]);
        return; }
#endif

  if(strcmp(Cmd,StrTBDM)==0)
    TraceBDM();
  else if(strcmp(Cmd,StrDRST)==0)
    BDMTraceReset();
  else if(strcmp(Cmd,StrTRST)==0)
  {
    TraceReset();
    TraceEnable(0);
  }
  else if(strcmp(Cmd,StrTBUF)==0)
    DumpTraceBuff();
  else if(strcmp(Cmd,StrDBUF)==0)
    DumpDebugBuff();
  else if(strcmp(Cmd,StrPST)==0)
    TestPST();
  else if(strcmp(Cmd,StrEPBK)==0)
  {

      TransmitByte('E');
      HexByteStr('=',&exceptBreak);
      TransmitByte(',');
      TransmitByte('A');
      TransmitByte('1');
      HexLongStr('=',BDMTempB);
      TransmitByte(',');
      TransmitByte('D');
      TransmitByte('1');
      HexWordStr('=',BDMTempB+6);
      TransmitByte(',');
      TransmitByte('A');
      TransmitByte('2');
      HexLongStr('=',BDMTempB+8);
      TransmitByte(',');
      TransmitByte('D');
      TransmitByte('2');
      HexWordStr('=',BDMTempB+14);
      TransmitByte(13);
      TransmitByte(10);
  }
  else if(strcmp(Cmd,StrREG)==0)
    TestReg(MemBuff);
  else if(strcmp(Cmd,StrSearch)==0)
    TestSearch();
  else if(strcmp(Cmd,StrCMPB)==0)
    TestCmp(0);
  else if(strcmp(Cmd,StrCMPW)==0)
    TestCmp(1);
  else if(strcmp(Cmd,StrCPYp)==0)
    TestCpy(0);
  else if(strcmp(Cmd,StrCPYm)==0)
    TestCpy(1);
  else if(*Cmd=='E')
    EditReg(Cmd+1);
  else if(strcmp(Cmd,StrDSH)==0)
    DebugShell();
  else if(strcmp(Cmd,StrKEY)==0)
    TestKeyBoard();
  else if(strcmp(Cmd,StrVER)==0)
  {
    BDMbuf=ShowVersion();
    HexLongStr(':',(U8*)&BDMbuf);
    TransmitByte(13);
    TransmitByte(10);
  }
  else if(strcmp(Cmd,StrPWM)==0)
    TestPWM();
  else if((*Cmd=='M')&&(Cmd[1]=='R'))
  {
    if(Cmd[2]==0)
    {
      SetMaxRetry(l=SetMaxRetry(0));
      HexByteStr('=',(U8*)&l);
      TransmitByte(13);
      TransmitByte(10);
    }
    else if(hex2bin(Cmd+2,&l))
      SendHexErr();
    else
      SetMaxRetry(l);
  }
  else if((*Cmd=='B')&&(Cmd[1]=='D')&&(Cmd[2]=='M'))
  {
    if(Cmd[3]==0)
    {
      HexByteStr('=',((U8*)&BDM_wait_cycle)+1);
      HexByteStr(0,(U8*)&BDM_wait_cycle);
      TransmitByte(13);
      TransmitByte(10);
    }
    else if(hex2word(Cmd+3,(U8*)&i))
      SendHexErr();
    else
      BDM_wait_cycle=i;
  }
  else if((*Cmd=='T')&&(Cmd[1]=='R'))
  {
    if(hex2long(Cmd+2,(U8*)&BDMbuf))
      SendHexErr();
    else for(;;)
    { delta=Clock;
      for(i=0;i<0x200;i++,BDMbuf+=0x80)
      {
        HexLongStr(13,(U8*)&BDMbuf);
        if(l=TestMem(BDMbuf,5,128,1))
        {
          TransmitByte(' ');
          if(l==2)
            PutStr(BDMerr);
          SendVerifyErr();
          return;
        }
      }
      delta-=Clock;
      BDMbuf-=2;
      HexLongStr(13,(U8*)&BDMbuf);
      BDMbuf+=2;
      TransmitByte(' ');
      PutStr(TestOK);
      SendTime(delta);
    }
  }
  else if((*Cmd=='T')&&((Cmd[1]=='W')||(Cmd[1]=='B')))
  {
    if(hex2long(Cmd+2,(U8*)&BDMbuf))
      SendHexErr();
    else
    { delta=Clock;
      for(i=0;i<0x200;i++,BDMbuf+=0x80)
      {
        HexLongStr(13,(U8*)&BDMbuf);
        if(l=TestMem(BDMbuf,5,128,(Cmd[1]=='B')?0:1))
        {
          TransmitByte(' ');
          if(l==2)
            PutStr(BDMerr);
          SendVerifyErr();
          return;
        }
      }
      delta-=Clock;
      BDMbuf-=((Cmd[1]=='B')?1:2);
      HexLongStr(13,(U8*)&BDMbuf);
      TransmitByte(' ');
      PutStr(TestOK);
      SendTime(delta);
    }
  }
  else if((*Cmd=='D')&&(Cmd[1]=='B'))
  {
    if(hex2long(Cmd+2,(U8*)&BDMbuf))
      SendHexErr();
    else
    {
      if(DumpByteMem(BDMbuf,5,128,MemBuff))
        PutStr(BDMerr);
      for(h=0;h<128;h+=16,BDMbuf+=16)
      {
        HexLongStr(0,(U8*)&BDMbuf);
        TransmitByte(':');
        for(l=h;l<(h+(U8)16);l++)
          HexByteStr(' ',MemBuff+l);
        asciiStr(MemBuff+h);
      }
    }
  }
  else if(*Cmd=='D')
  {
    if(Cmd[1]=='W')
    {
      if(hex2long(Cmd+2,(U8*)&BDMbuf))
      {
        SendHexErr();
        return;
      }
    }
    else if(hex2long(Cmd+1,(U8*)&BDMbuf))
    {
        SendHexErr();
        return;
    }
    if(DumpWordMem(BDMbuf,5,128,MemBuff))
      PutStr(BDMerr);
    for(h=0;h<128;h+=16,BDMbuf+=16)
    {
      HexLongStr(0,(U8*)&BDMbuf);
      TransmitByte(':');
      for(l=h;l<(h+(U8)16);l+=2)
        HexWordStr(' ',MemBuff+l);
      asciiStr(MemBuff+h);
    }
  }
  else if((*Cmd=='W')&&(Cmd[1]=='C'))
  {
    if(hex2long(Cmd+2,(U8*)&BDMbuf))
      SendHexErr();
    else
    {
      if(l=FillCode(BDMbuf))
      {
        if(l==2)
          PutStr(BDMerr);
        SendVerifyErr();
      }
      else
        PutStr(FillOK);
    }
  }
  else if((*Cmd=='F')&&(Cmd[1]=='B'))
  {
    if(hex2long(Cmd+2,(U8*)&BDMbuf))
      SendHexErr();
    else
    { l=0;
      TransmitByte('S');
      TransmitByte('t');
      TransmitByte('r');
      TransmitByte('i');
      TransmitByte('n');
      TransmitByte('g');
      TransmitByte(':');
      TransmitByte(' ');
      if(str=GetStr(0))
        for(l=0;str[l];l++)
          MemBuff[l]=str[l];
      else
      {
        PutStr(CmdAbort);
        return;
      }
      if(l==0)
        for(l=0;l<2;l++)
          MemBuff[l]=0;
      if(l=FillByteMem(BDMbuf,5,128,l,MemBuff,1))
      {
        if(l==2)
          PutStr(BDMerr);
        SendVerifyErr();
      }
      else
        PutStr(FillOK);
    }
  }
  else if(*Cmd=='F')
  {
    if(hex2long(Cmd+1,(U8*)&BDMbuf))
      SendHexErr();
    else
    { l=0;
      TransmitByte('S');
      TransmitByte('t');
      TransmitByte('r');
      TransmitByte('i');
      TransmitByte('n');
      TransmitByte('g');
      TransmitByte(':');
      TransmitByte(' ');
      if(str=GetStr(0))
        for(l=0;str[l];l++)
          MemBuff[l]=str[l];
      else
      {
        PutStr(CmdAbort);
        return;
      }
      if(l==0)
        for(l=0;l<2;l++)
          MemBuff[l]=0;
      else if(l&1)
        MemBuff[l++]=0;
      if(l=FillWordMem(BDMbuf,5,128,l,MemBuff,1))
      {
        if(l==2)
          PutStr(BDMerr);
        SendVerifyErr();
      }
      else
        PutStr(FillOK);
    }
  }
  else if((*Cmd=='S')&&(Cmd[1]=='L'))
  {
    if(hex2long(Cmd+2,MemBuff))
      SendHexErr();
    else
    {
      TestBDMLong(MemBuff);
      TransmitByte('R');
      TransmitByte(bin2hex[15&MemBuff[6]]);
      HexByteStr(0,MemBuff+5);
      HexByteStr(0,MemBuff+4);
      HexByteStr('(',BDMTempB+1);
      HexByteStr(0,BDMTempB);
      TransmitByte(')');
      TransmitByte(13);
      TransmitByte(10);
      TransmitByte('R');
      TransmitByte(bin2hex[15&MemBuff[2]]);
      HexByteStr(0,MemBuff+1);
      HexByteStr(0,MemBuff);
      HexByteStr('(',BDMTempB+3);
      HexByteStr(0,BDMTempB+2);
      TransmitByte(')');
      TransmitByte(13);
      TransmitByte(10);
    }
  }
  else if(*Cmd=='S')
  {
    if(hex2bin(Cmd+1,&h)||hex2bin(Cmd+3,&l))
      SendHexErr();
    else
    {
      BDMbuf=(h<<8)+l;
      TestBDM(&BDMbuf);
      TransmitByte('R');
      TransmitByte(bin2hex[15&(BDMbuf>>16)]);
      TransmitByte(bin2hex[15&(BDMbuf>>12)]);
      TransmitByte(bin2hex[15&(BDMbuf>>8)]);
      TransmitByte(bin2hex[15&(BDMbuf>>4)]);
      TransmitByte(bin2hex[BDMbuf&15]);
      HexByteStr('(',BDMTempB+1);
      HexByteStr(0,BDMTempB);
      TransmitByte(')');
      TransmitByte(13);
      TransmitByte(10);
    }
  }
  else if((*Cmd=='A')&&((Cmd[1]=='L')||(Cmd[1]=='H')||(Cmd[1]=='W')))
  { delta=0;
    if(hex2bin(Cmd+2,&h)||hex2bin(Cmd+4,&l))
      SendHexErr();
    else for(;;)
    { SetDmaCount(1);
      BDMbuf=(h<<8)+l;
      if(Cmd[1]=='L')
        TestBDM_L(&BDMbuf);
      else if(Cmd[1]=='H')
        TestBDM_H(&BDMbuf);
      else
        TestBDM(&BDMbuf);
      TransmitByte('R');
      TransmitByte(bin2hex[15&(BDMbuf>>16)]);
      TransmitByte(bin2hex[15&(BDMbuf>>12)]);
      TransmitByte(bin2hex[15&(BDMbuf>>8)]);
      TransmitByte(bin2hex[15&(BDMbuf>>4)]);
      TransmitByte(bin2hex[BDMbuf&15]);
      TransmitByte(' ');
      HexByteStr('(',BDMTempB+1);
      HexByteStr(0,BDMTempB);
      TransmitByte(':');
      TransmitByte(bin2hex[15&(delta>>16)]);
      TransmitByte(bin2hex[15&(delta>>12)]);
      TransmitByte(bin2hex[15&(delta>>8)]);
      TransmitByte(bin2hex[15&(delta>>4)]);
      TransmitByte(bin2hex[delta&15]);
      delta++;
      TransmitByte(')');
      TransmitByte(13);
      TransmitByte(10);
      if(ReceiveByte()==' ')
        return;
    }
  }
  else if(*Cmd=='I')
  {
    if(hex2long(Cmd+1,MemBuff))
      SendHexErr();
    else
    {
      IntStr(*(U32*)MemBuff);
      TransmitByte(13);
      TransmitByte(10);
    }
  }
  else if((*Cmd=='H')||(*Cmd=='h')||(*Cmd=='?'))
    HelpMsg();
  else if(strcmp(Cmd,StrRST)==0)
  {
    TransmitByte('W');
    TransmitByte('R');
    TransmitByte('O');
    TransmitByte('M');
    TransmitByte('"');
    TransmitByte(']');
    TransmitByte(']');
    TransmitByte('"');
    TransmitByte(',');
    TransmitByte('D');
    TransmitByte('B');
    TransmitByte('U');
    TransmitByte('G');
    TransmitByte('"');
    TransmitByte('_');
    TransmitByte('_');
    TransmitByte('"');
    TransmitByte(13);
    TransmitByte(10);
    SetWatchDog(12);
    for(timeOut=0;timeOut==0;);
    FwReset();
  }
  else
  {
    TransmitByte('?');
    TransmitByte(7);
    TransmitByte(13);
    TransmitByte(10);
  }
}

void Dbug(void)
{ U8 *Cmd;
  U8 HexStr[]={'0','1','2','3','4','5','6','7',
               '8','9','A','B','C','D','E','F'};
  bin2hex=HexStr;
  for(;;)
  {
    TransmitByte('>');
    if(Cmd=GetStr(1))
      TestCmd(Cmd);
  }
}

void EngTest(void)
{
  SetWatchDog(100);
  for(timeOut=0;timeOut==0;);
  SendTitle();
  ShowVersion();
  Dbug();
}

void PutStr(U8 *Str)
{ if(Str)
    while(*Str)
      TransmitByte(*Str++);
  TransmitByte(13);
  TransmitByte(10);
}

void asciiStr(U8 *Buff)
{ int i;
  TransmitByte(' ');
  for(i=0;i<16;i++)
    if(isprint(Buff[i]))
      TransmitByte(Buff[i]);
    else
      TransmitByte('.');
  TransmitByte(13);
  TransmitByte(10);
}

U8 *GetStr(U8 flag)
{ int i=0;
  static U8 buf[GetStrBufSize+1];
  U8 c;
  for(;;)
  {
    SetDmaCount(1);
    c=ReceiveByte();
    if(timeOut)
      continue;
    if(c==27)
    { TransmitByte('\\');
      TransmitByte(13);
      TransmitByte(10);
      return 0; }
    else if(c==13)
    { TransmitByte(13);
      TransmitByte(10);
      buf[i]=0;
      return buf; }
    else if(c==8)
    { if(i==0)
        TransmitByte(7);
      else
      { i--;
        TransmitByte(8); }}
    else if(c==127)
    { if(i==0)
        TransmitByte(7);
      else
      { i--;
        TransmitByte(8);
        TransmitByte(' ');
        TransmitByte(8); }}
    else if(i==GetStrBufSize)
      TransmitByte(7);
    else if(flag==0)
      TransmitByte(buf[i++]=c);
    else if(('a'<=c)&&(c<='z'))
      TransmitByte(buf[i++]=(c+=('A'-'a')));
    else
      TransmitByte(buf[i++]=c);
  }
}

U16 hex2bin(U8 *hex,U8 *bin)
{ if(('0'<=hex[0])&&(hex[0]<='9'))
    *bin=(U8)(hex[0]-'0');
  else if(('A'<=hex[0])&&(hex[0]<='F'))
    *bin=(U8)(hex[0]-'A'+10);
  else if(('a'<=hex[0])&&(hex[0]<='f'))
    *bin=(U8)(hex[0]-'a'+10);
  else
    return 1;
  *bin=(U8)((*bin)<<4);
  if(('0'<=hex[1])&&(hex[1]<='9'))
    *bin+=(hex[1]-'0');
  else if(('A'<=hex[1])&&(hex[1]<='F'))
    *bin+=(hex[1]-'A'+10);
  else if(('a'<=hex[1])&&(hex[1]<='f'))
    *bin+=(hex[1]-'a'+10);
  else
    return 1;
  return 0;
}

U16 hex2long(U8 *hex,U8 *bin)
{
 return(hex2bin(hex  ,bin+3)||
        hex2bin(hex+2,bin+2)||
        hex2bin(hex+4,bin+1)||
        hex2bin(hex+6,bin));
}

U16 hex2word(U8 *hex,U8 *bin)
{
 return(hex2bin(hex  ,bin+1)||
        hex2bin(hex+2,bin));
}

U16 hex2meml(U8 *hex,U8 *bin)
{
 return(hex2bin(hex  ,bin  )||
        hex2bin(hex+2,bin+1)||
        hex2bin(hex+4,bin+2)||
        hex2bin(hex+6,bin+3));
}

void SendHexErr(void)
{
  TransmitByte('H');
  TransmitByte('e');
  TransmitByte('X');
  TransmitByte('E');
  TransmitByte('r');
  TransmitByte('r');
  TransmitByte(7);
  TransmitByte(13);
  TransmitByte(10);
}

void SendVerifyErr(void)
{ int i;
  TransmitByte('V');
  TransmitByte('e');
  TransmitByte('r');
  TransmitByte('i');
  TransmitByte('f');
  TransmitByte('y');
  TransmitByte(' ');
  TransmitByte('E');
  TransmitByte('r');
  TransmitByte('r');
  TransmitByte('o');
  TransmitByte('r');
  TransmitByte(' ');
  TransmitByte('a');
  TransmitByte('t');
  TransmitByte(' ');
  for(i=4;i>0;i--)
  { TransmitByte(bin2hex[BDMTempB[i-1]>>4]);
    TransmitByte(bin2hex[BDMTempB[i-1]&15]); }
  TransmitByte(' ');
  TransmitByte('(');
  TransmitByte('R');
  TransmitByte(':');
  for(i=2;i>0;i--)
  { TransmitByte(bin2hex[BDMTempB[i+3]>>4]);
    TransmitByte(bin2hex[BDMTempB[i+3]&15]); }
  TransmitByte(',');
  TransmitByte('W');
  TransmitByte(':');
  for(i=2;i>0;i--)
  { TransmitByte(bin2hex[BDMTempB[i+5]>>4]);
    TransmitByte(bin2hex[BDMTempB[i+5]&15]); }
  TransmitByte(')');
  TransmitByte(13);
  TransmitByte(10);
}

void HexByteStr(U8 ch,U8 *buff)
{
  if(ch)
    TransmitByte(ch);
  TransmitByte(bin2hex[buff[0]>>4]);
  TransmitByte(bin2hex[buff[0]&15]);
}

void HexWordStr(U8 ch,U8 *buff)
{ int i;
  if(ch)
    TransmitByte(ch);
  for(i=0;i<2;i++)
  {
    TransmitByte(bin2hex[buff[i]>>4]);
    TransmitByte(bin2hex[buff[i]&15]);
  }
}

void HexLongStr(U8 ch,U8 *buff)
{ int i;
  if(ch)
    TransmitByte(ch);
  for(i=4;i>0;i--)
  {
    TransmitByte(bin2hex[buff[i-1]>>4]);
    TransmitByte(bin2hex[buff[i-1]&15]);
  }
}

void TestReg(U8* buff)
{ int i;
  GetReg((U32*)buff);

  TransmitByte('A');
  TransmitByte('n');
  TransmitByte(':');
  for(i=6;i>=0;i--)
    HexLongStr(' ',buff+i*4);
  TransmitByte(13);
  TransmitByte(10);

  TransmitByte('D');
  TransmitByte('n');
  TransmitByte(':');
  for(i=14;i>=7;i--)
    HexLongStr(' ',buff+i*4);
  TransmitByte(13);
  TransmitByte(10);

  TransmitByte('S');
  TransmitByte('P');
  TransmitByte(':');
  HexLongStr(0,buff+15*4);
  TransmitByte(' ');

  TransmitByte('S');
  TransmitByte('R');
  TransmitByte(':');
  HexLongStr(0,buff+16*4);
  TransmitByte(' ');

  TransmitByte('P');
  TransmitByte('C');
  TransmitByte(':');
  HexLongStr(0,buff+17*4);
  TransmitByte(' ');

  TransmitByte('V');
  TransmitByte('B');
  TransmitByte('R');
  TransmitByte(':');
  HexLongStr(0,buff+18*4);
  TransmitByte(13);
  TransmitByte(10);
}

U16 GetRegNum(U8 *RegName)
{ U8 StrSP[]={'S','P',0};
  U8 StrSR[]={'S','R',0};
  U8 StrPC[]={'P','C',0};
  U8 StrVBR[]={'V','B','R',0};
  U8 StrCSR[]={'C','S','R',0};
  U8 StrAABR[]={'A','A','B','R',0};
  U8 StrTDR[]={'T','D','R',0};
  U8 StrPBR[]={'P','B','R',0};
  U8 StrPBMR[]={'P','B','M','R',0};
  U8 StrABHR[]={'A','B','H','R',0};
  U8 StrABLR[]={'A','B','L','R',0};
  U8 StrDBR[]={'D','B','R',0};
  U8 StrDBMR[]={'D','B','M','R',0};
  U8 StrCCR[]={'C','A','C','R',0};
  U8 StrACR0[]={'A','C','R','0',0};
  U8 StrACR1[]={'A','C','R','1',0};
  U8 StrRBAR[]={'R','A','M','B','A','R',0};
  U8 StrMBAR[]={'M','B','A','R',0};
  U8 *NameAry[]={StrSP,StrSR,StrPC,StrVBR,
                 StrCSR,StrAABR,StrTDR,StrPBR,StrPBMR,
                 StrABHR,StrABLR,StrDBR,StrDBMR,
                 StrCCR,StrACR0,StrACR1,StrRBAR,StrMBAR,0};
  U16 NumAry[]={REG_SP,REG_SR,REG_PC,REG_VBR,
                REG_CSR,REG_AABR,REG_TDR,REG_PBR,REG_PBMR,
                REG_ABHR,REG_ABLR,REG_DBR,REG_DBMR,
                REG_CCR,REG_ACR0,REG_ACR1,REG_RAMBAR,REG_MBAR};
  int i;
  for(i=0;NameAry[i];i++)
    if(strcmp(RegName,NameAry[i])==0)
      return NumAry[i];
  if(*RegName=='A')
    if(('0'<=RegName[1])&&(RegName[1]<='6'))
      return REG_A0-RegName[1]+'0';
  if(*RegName=='D')
    if(('0'<=RegName[1])&&(RegName[1]<='7'))
      return REG_D0-RegName[1]+'0';
  return 0xffff;
}

void EditReg(U8 *RegName)
{ U8 buff[4],*Str;
  U16 RegNum;
  if((RegNum=GetRegNum(RegName))==0xffff)
  { TransmitByte('E');
    TransmitByte('r');
    TransmitByte('r');
    TransmitByte('R');
    TransmitByte('e');
    TransmitByte('g');
    TransmitByte(7);
    TransmitByte(13);
    TransmitByte(10); }
  else
  { ReadReg(RegNum,(U32*)buff);
    HexLongStr(0,buff);
    TransmitByte(' ');
    TransmitByte('-');
    TransmitByte('>');
    TransmitByte(' ');
    if((Str=GetStr(1))==0)
      return;
    if(hex2bin(Str,buff+3)||hex2bin(Str+2,buff+2)||
       hex2bin(Str+4,buff+1)||hex2bin(Str+6,buff))
      SendHexErr();
    else
      WriteReg(RegNum,*(U32*)buff);
  }
}

void ECHO(void)
{ int i;
  U8 c;
  for(;;)
  {
    SetDmaCount(4);
    for(i=0;i<4;i++)
    {
      c=ReceiveByte();
      if(timeOut)
        break;
      else
        TransmitByte(c);
    }
  }
}

void HEXCH(void)
{ int i;
  U8 c;
  for(;;)
  {
    SetDmaCount(4);
    for(i=0;i<4;i++)
    {
      c=ReceiveByte();
      if(timeOut)
        break;
      else
      {
        TransmitByte(' ');
        TransmitByte(bin2hex[15&(c>>4)]);
        TransmitByte(bin2hex[c&15]);
      }
      if(c==3)
      {
        SetWatchDog(3);
        for(timeOut=0;timeOut==0;);
        return;
      }
    }
  }
}

void TestCmp(U16 f)
{ U32 a1,a2;
  U16 l;
  U8 *s;
  TransmitByte('A');
  TransmitByte('1');
  TransmitByte(':');
  if((s=GetStr(1))==0)
    return;
  if(hex2long(s,(U8*)&a1))
  { SendHexErr();
    return; }
  TransmitByte('A');
  TransmitByte('2');
  TransmitByte(':');
  if((s=GetStr(1))==0)
    return;
  if(hex2long(s,(U8*)&a2))
  { SendHexErr();
    return; }
  TransmitByte('L');
  TransmitByte('e');
  TransmitByte('n');
  TransmitByte(':');
  if((s=GetStr(1))==0)
    return;
  if(hex2word(s,(U8*)&l))
  { SendHexErr();
    return; }
  s[0]=CompareMem(a1,5,l,a2,5,f);
  HexByteStr(0,s);
  HexLongStr(' ',BDMTempB);
  HexWordStr(' ',BDMTempB+4);
  HexWordStr(' ',BDMTempB+6);
  HexLongStr(' ',BDMTempB+8);
  HexWordStr(' ',BDMTempB+12);
  HexWordStr(' ',BDMTempB+14);
  TransmitByte(13);
  TransmitByte(10);
}

void TestCpy(U16 f)
{ U32 a1,a2;
  U16 l;
  U8 *s;
  for(;;)
  {
    TransmitByte('A');
    TransmitByte('1');
    TransmitByte(':');
    if((s=GetStr(1))==0)
      return;
    if(hex2long(s,(U8*)&a1))
      SendHexErr();
    else
      break;
  }
  for(;;)
  {
    TransmitByte('A');
    TransmitByte('2');
    TransmitByte(':');
    if((s=GetStr(1))==0)
      return;
    if(hex2long(s,(U8*)&a2))
      SendHexErr();
    else
      break;
  }
  for(;;)
  {
    TransmitByte('L');
    TransmitByte('e');
    TransmitByte('n');
    TransmitByte(':');
    if((s=GetStr(1))==0)
      return;
    if(hex2word(s,(U8*)&l))
      SendHexErr();
    else
      break;
  }
  if(f)
    s[0]=PostCopyMem(a1,5,l,a2,5,1);
  else
    s[0]=PreCopyMem(a1,5,l,a2,5,1);
  HexByteStr(0,s);
  HexLongStr(' ',BDMTempB);
  HexWordStr(' ',BDMTempB+4);
  HexWordStr(' ',BDMTempB+6);
  HexLongStr(' ',BDMTempB+8);
  HexWordStr(' ',BDMTempB+12);
  HexWordStr(' ',BDMTempB+14);
  TransmitByte(13);
  TransmitByte(10);
}

void TestSearch()
{ U32 a;
  U16 l1,l2;
  U8 Buf[128];
  U8 *s;
  TransmitByte('S');
  TransmitByte('t');
  TransmitByte('r');
  TransmitByte('i');
  TransmitByte('n');
  TransmitByte('g');
  TransmitByte(':');
  TransmitByte(' ');
  if((s=GetStr(0))==0)
    return;
  for(l2=0;s[l2];l2++)
    Buf[l2]=s[l2];
  if(l2==0)
    return;
  TransmitByte('A');
  TransmitByte('d');
  TransmitByte('d');
  TransmitByte('r');
  TransmitByte(':');
  if((s=GetStr(1))==0)
    return;
  if(hex2long(s,(U8*)&a))
  { SendHexErr();
    return; }
  TransmitByte('L');
  TransmitByte('e');
  TransmitByte('n');
  TransmitByte(':');
  if((s=GetStr(1))==0)
    return;
  if(hex2word(s,(U8*)&l1))
  { SendHexErr();
    return; }
  s[0]=SearchMem(a,5,l1,l2,Buf);
  HexByteStr(0,s);
  HexLongStr(' ',BDMTempB);
  TransmitByte(13);
  TransmitByte(10);
}

void TestKeyBoard()
{ U8 Ch;
  U8 ESC_MSG[]={'P','r','e','s','s',' ','<','E','S','C','>',' ','t','o',' ',
                'e','x','i','t','!',0};
  PutStr(ESC_MSG);
  for(;;)
  {
    SetDmaCount(1);
    Ch=ReceiveByte();
    if(timeOut)
      continue;
    HexByteStr(' ',&Ch);
    if(Ch==27)
    {
      TransmitByte(13);
      TransmitByte(10);
      SetWatchDog(3);
      for(timeOut=0;timeOut==0;);
      return;
    }
  }
}

void IntStr(U32 x)
{ U32 y;
  U8 s[10],i=0;
  do
  { s[i++]=(U8)(x-(y=(x/10))*10);
  }while((x=y)!=0);
  while(i)
    TransmitByte((U8)(s[--i]+'0'));
}

void Chg_PWM(U16 ctrl,U16 cmpa,U16 cmpb,U32 freq,U32 scal)
{ U32 x;
  U8 vec,s[]={'K','M'};
  Set_PWM(ctrl,cmpa,cmpb);
  for(vec=2; vec && (freq<scal); vec--)
    freq*=1000;
  IntStr(x=(freq/scal));
  if((x=(freq-x*scal))!=0)
  { TransmitByte('.');
    IntStr(x*1000/scal);
  }
  if(vec)
    TransmitByte(s[vec-1]);
  TransmitByte('H');
  TransmitByte('z');
  TransmitByte(13);
  TransmitByte(10);
}

#define w2d(x) ((x)?(U32)(x):0x10000)
void TestPWM()
{ U8 *Cmd;
  U16 CMPa,CMPb;
  U8 PWM_hlp[]={ 7,
                'O',' ',' ',' ',' ',' ',' ',' ',' ',' ','-',' ',
                't','u','r','n',' ','o','f','f',13,10,
                'W','<','x','>',' ',' ',' ',' ',' ',' ','-',' ',
                's','w','i','t','c','h','i','n','g',13,10,
                'S','<','x','>',' ',' ',' ',' ',' ',' ','-',' ',
                '4','M','H','z',' ','/',' ','x',13,10,
                'P','<','x','>',',','<','y','>',' ',' ','-',' ',
                '4','M','H','z',' ','/',' ','(','x','+','y',')',13,10,
                '<','x','>',' ',' ',' ',' ',' ',' ',' ','-',' ',
                '4','M','H','z',' ','/',' ','(','2','*','x',')',0};
  BaudRate(Baud_96);
  for(;;)
  {
    TransmitByte('@');
    if(Cmd=GetStr(1))
      switch(*Cmd)
      {
        case 0:
        case 'H':
        case '?':
          PutStr(PWM_hlp);
          break;
        case 'O':
          Set_PWM(0,0,0);
          break;
        case 'W':
          CMPa=CMPb=1;
          if(hex2bin(Cmd+1,(U8*)&CMPb))
            SendHexErr();
          else if(CMPb==0)
            SendHexErr();
          else do
          { SetDmaCount(1);
            SetWatchDog(100);
            Chg_PWM(0xC003,CMPa,CMPa,2,w2d(CMPa));
            CMPa=(CMPa>=1000)?1:(CMPa*CMPb);
          }while(ReceiveByte()!=' ');
          break;
        case 'S':
          if(hex2word(Cmd+1,(U8*)&CMPa))
            SendHexErr();
          else
            Chg_PWM(0xC001,CMPa,0,4,w2d(CMPa));
          break;
        case 'P':
          if(hex2word(Cmd+1,(U8*)&CMPa)||hex2word(Cmd+5,(U8*)&CMPb))
            SendHexErr();
          else
            Chg_PWM(0xC003,CMPa,CMPb,4,w2d(CMPa)+w2d(CMPb));
          break;
        default:
          if(hex2word(Cmd,(U8*)&CMPa))
            SendHexErr();
          else
            Chg_PWM(0xC003,CMPa,CMPa,2,w2d(CMPa));
      }
  }
}
