gonzui


Format: Advanced Search

tkernel_2/monitor/cmdsvc/src/command.cbare sourcepermlink (0.17 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T-Kernel 2.0 Software Package
    4:  *
    5:  *    Copyright 2011 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2011/05/17.
   10:  *    Modified by T-Engine Forum at 2013/03/04.
   11:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/01.
   12:  *
   13:  *----------------------------------------------------------------------
   14:  */
   15: 
   16: /*
   17:  *      command.c
   18:  *
   19:  *       command processing
   20:  */
   21: 
   22: #include "cmdsvc.h"
   23: #include "help.h"
   24: #include <tk/dbgspt.h>
   25: 
   26: #define DEF_MEM_SIZE    64         // default memory dump size
   27: #define DEF_DA_STEP     16          // default disassbmle size
   28: #define MAX_DSP_CNT     64          // maximum cut off count for display
   29: #define MAX_RANGE       0x1000000     // maximum range (16 MB)
   30: #define IMPLICIT_SIZE   0x1000            // implicit size specification
   31: 
   32: EXPORT  UB       lineBuf[L_LINE];      // line buffer
   33: EXPORT  W        killProcReq;           // request to forcibly kill a process
   34: 
   35: #define L_SYMBOL        23             // effective symbol length
   36: #define SETDT_SZ        128            // data size
   37: 
   38: #define CMD_FINISH      (9999)               // command end specification
   39: 
   40: EXPORT  W        errinfo;               // error information
   41: LOCAL   W errcode;                // error code
   42: 
   43: LOCAL   UW        dAddr;                 // D address command
   44: LOCAL   UW        mAddr;                 // M command address
   45: LOCAL   UW        daAddr;                        // DA command address
   46: LOCAL   UW        cAddr;                 // the current start address
   47: LOCAL   W cLen;                   // the current memory byte length
   48: 
   49: LOCAL   W token;                  // token type
   50: LOCAL   UW        tokenVal;              // numeric token / register number
   51: LOCAL   UB        *tokenStr;             // character string / symbol item pointer
   52: LOCAL   W tokenLen;               // character string / symbol item length
   53: LOCAL   UB        tokenSym[L_SYMBOL + 1];        // symbol item string(capital letters)
   54: LOCAL   UB        symExt[2];             // extended symbol letters
   55: LOCAL   UB        *lptr;                 // line pointer
   56: 
   57: #define PROMPT  "TM> "                   // prompt
   58: 
   59: // item type
   60: #define tEOL            0x00              // line end
   61: #define tEOC            0x01              // end of command
   62: #define tDLM            0x02              // delimiter
   63: #define tSIZ            0x11              // size specification
   64: #define tOPADD          0x12            // + operator
   65: #define tOPSUB          0x13            // - operator
   66: #define tOPMUL          0x14            // * operator
   67: #define tOPDIV          0x15            // / operator
   68: #define tOPIND          0x16            // & operator
   69: #define tEOD            0x17              // end of data
   70: #define tUP             0x18               // previous data
   71: #define tSYM            0x20              // symbol
   72: #define tNUM            0x21              // numeric value
   73: #define tSTR            0x22              // character string
   74: #define tERRR           0x100            // error
   75: #define tERCH           0x100            // error: illegal character
   76: #define tERNUM          0x101           // error: illegal numeric form
   77: 
   78: // character classficiation
   79: #define isSpace(c)              ((c) && (c) <= ' ')
   80: #define isNum(c)                ((c) >= '0' && (c) <= '9')
   81: #define isAlpha(c)              ( ((c) >= 'A' && (c) <= 'Z') ||\
   82:                                         ((c) >= 'a' && (c) <= 'z') )
   83: #define isAlNum(c)              (isNum(c) || isAlpha(c))
   84: #define isSym(c)                (isAlpha(c) || c == '$' || c == '_' ||\
   85:                                         c == '?' || c == '@')
   86: #define isExtSym(c)             ((c) && ((c) == symExt[0] || (c) == symExt[1]))
   87: 
   88: // alignment adjustment
   89: #define ALIGN_L(v, unit)        ((v) & ~((unit) - 1))
   90: #define ALIGN_U(v, unit)        (((v) + (unit) - 1) & ~((unit) - 1))
   91: 
   92: // error return
   93: #define return_er(er)           return (errcode = er)
   94: #define er_return(er)           {errcode = er; return;}
   95: #define oer_return(er)          {if ((er) == E_NOEXS)\
   96:                                         errcode = E_ONOEXS;\
   97:                                  else   errcode = er;\
   98:                                  return;}
   99: 
  100: #define DB16            0x00000           // default base number
  101: #define DB10            0x10000
  102: 
  103: /*
  104:         display error message
  105: */
  106: LOCAL   void      dspError(void)
  107: {
  108:         UB     *mp = NULL;
  109: 
  110:         if (token >= tERRR) {  // priortize the item error
  111:                 switch(token) {
  112:                 case tERCH:   mp = "Illegal Character";         break;
  113:                 case tERNUM:  mp = "Illegal Number Format";            break;
  114:                 }
  115:         } else {
  116:                 if (errinfo < 0) errcode = errinfo;
  117:                 switch(errcode) {
  118:                 case E_MACV:  mp = "Illegal Address";                  break;
  119:                 case E_ROM:   mp = "ROM Address";                       break;
  120:                 case E_LESS:  if (token <= tEOC)
  121:                                         {mp = "Less Parameter";    break;}
  122:                 case E_PAR:   mp = "Illegal Parameter";         break;
  123:                 case E_ID:    mp = "Illegal ID Number";          break;
  124:                 case E_CTX:   mp = "Context Error";                     break;
  125:                 case E_LIMIT: mp = "Too Many Parameters";             break;
  126:                 case E_OBJ:   mp = "Abnormal Object Status";            break;
  127:                 case E_NOSPT: mp = "Not Supported";                   break;
  128:                 case E_NOEXS: mp = "Unknown Device";                  break;
  129:                 case E_IO:    mp = "I/O Error";                  break;
  130:                 case E_RONLY: mp = "Read Only";                       break;
  131:                 case E_NOMDA: mp = "No Media";                        break;
  132:                 case E_PROTECT:       mp = "Write Protected";                       break;
  133: 
  134:                 case E_CMD:   mp = "Unknown Command";                   break;
  135:                 case E_RANGE: mp = "Illegal Address Range";           break;
  136:                 case E_EMPTY: mp = "Empty String";                    break;
  137:                 case E_ILREG: mp = "Unknown Register Name";           break;
  138:                 case E_PC:    mp = "Illegal PC Value";           break;
  139:                 case E_BOOT:  mp = "No Bootable Disk";         break;
  140: 
  141:                 case E_PROTO: mp = "Unknown Load Protocol";           break;
  142:                 case E_NOADDR:        mp = "No Load Address";                        break;
  143:                 case E_LOADFMT:       mp = "Illegal S-Format Record";               break;
  144:                 case E_LOAD:  mp = "Loading Error";                    break;
  145:                 case E_CANCEL:        mp = "Loading Cancelled";              break;
  146:                 case E_XMODEM:        mp = "XMODEM Protocol Error";          break;
  147: 
  148:                 case E_BPATR: mp = "Unknown Break Point Attribute";   break;
  149:                 case E_BPBAD: mp = "Illegal Break Point";             break;
  150:                 case E_BPDSLT:        mp = "Break Point at Delayed Slot";    break;
  151:                 case E_BPROM: mp = "Break Point in ROM";              break;
  152:                 case E_BPCMD: mp = "Too Long Break Point Command";    break;
  153:                 case E_BPUDF: mp = "Undefined Break Point";           break;
  154:                 case E_SBPOVR:        mp = "Too Many Software Break Points"; break;
  155:                 case E_HBPOVR:        mp = "Too Many Hardware Break Points"; break;
  156: 
  157:                 case E_ONOEXS:  mp = "Noexistent Object";             break;
  158:                 }
  159:         }
  160:         if (mp) {
  161:                 DSP_F3(S,"ERR: ", S,mp, CH,'\n');
  162:         } else {
  163:                 DSP_F3(S,"ERR: [", 08X,errcode, S,"]\n");
  164:         }
  165: }
  166: /*
  167:         input of a line
  168: */
  169: LOCAL   W getLine(UB *msg)
  170: {
  171:         if (msg) DSP_S(msg);                   // display prompt
  172:         memset(lineBuf, 0, sizeof(lineBuf));   // clear buffer
  173:         return getString(lptr = lineBuf);      // input a line and initialize the line pointer
  174: }
  175: /*
  176:         skip spaces
  177: */
  178: LOCAL   void      skipSpace(void)
  179: {
  180:         while (isSpace(*lptr)) lptr++;
  181: }
  182: /*
  183:         extract hexadecimal value
  184: */
  185: LOCAL   W getHexVal(UB **ptr)
  186: {
  187:         W      c;
  188:         UW     v;
  189:         UB     *p;
  190: 
  191:         p = *ptr;
  192:         for (v = 0; ((c = *p) >= '0' && c <= '9') ||
  193:                 (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); p++) {
  194:                 if (v >= 0x10000000) break;   // overflow
  195:                 v <<= 4;
  196:                 v += (c >= 'a' ? (c - 'a' + 10) :
  197:                              (c >= 'A' ? (c - 'A' + 10) : ( c - '0')));
  198:         }
  199:         *ptr = p;
  200:         return v;
  201: }
  202: /*
  203:         extract item
  204: 
  205:         numerical constant:   H'<digit>  0x<digit>  hexadecimal
  206:                         D'<digital>                  decimal (base 10)
  207:                         Q'<digit>                  octal (base 8)
  208:                         B'<digit>                  binary(base 2)
  209:                         <digit>            '<digit>           hexadecimal(base 16)
  210:         character constant:  "<character>.."        only ASCII characters are allowed
  211:         symbol:   <letter$_><letter$_digit>..
  212:         operator:       +       addition
  213:                         -       subtraction
  214:                         *        multiplication
  215:                         /       division
  216:                         &       indirect reference
  217:         separator:      ,
  218:         special symbol: ;       EndOfCommand(same as EndOfLine)
  219:                         #       size specificication
  220:                         .       end of data
  221:                         ^       UP (return to previous line)
  222: */
  223: LOCAL   W getToken(W defbase)
  224: {
  225:         W      c, i, base;
  226: 
  227:         tokenVal = 0;
  228:         skipSpace();
  229:         if ((c = *lptr) == 0)  {i = tEOL;       goto EXIT;}
  230:         lptr++;
  231: 
  232:         if (c == ';')          {i = tEOC;      goto EXIT;}
  233:         if (c == ',')          {i = tDLM;      goto EXIT;}
  234:         if (c == '#')          {i = tSIZ;      goto EXIT;}
  235:         if (c == '.')          {i = tEOD;      goto EXIT;}
  236:         if (c == '^')          {i = tUP;       goto EXIT;}
  237:         if (c == '+')          {i = tOPADD;    goto EXIT;}
  238:         if (c == '-')          {i = tOPSUB;    goto EXIT;}
  239:         if (c == '*')          {i = tOPMUL;    goto EXIT;}
  240:         if (c == '/')          {i = tOPDIV;    goto EXIT;}
  241:         if (c == '&')          {i = tOPIND;    goto EXIT;}
  242: 
  243:         if (c == '"') {                // character string
  244:                 for (tokenStr = lptr; (c = *lptr) && c != '"'; lptr++);
  245:                 tokenLen = lptr - tokenStr;
  246:                 if (c) lptr++;
  247:                 i = tSTR;
  248:                 goto EXIT;
  249:         }
  250: 
  251:         if (*lptr == '\'') {   // number with prefix
  252:                 if (c == 'Q' || c == 'q') {base = 8;  goto NUMVAL;}
  253:                 if (c == 'B' || c == 'b') {base = 2;  goto NUMVAL;}
  254:                 if (c == 'D' || c == 'd') {base = 10;
  255: NUMVAL:
  256:                         while ((c = *++lptr) >= '0' && c < base + '0')
  257:                                 tokenVal = tokenVal * base + c - '0';
  258:                         goto NUMEXIT;
  259:                 }
  260:                 if (c == 'H' || c == 'h') goto HEXVAL;
  261:         }
  262: 
  263:         if (isNum(c)) {                // simple number
  264:                 if (c != '0' || (*lptr != 'x' && *lptr != 'X')) {
  265:                         lptr -= 2;
  266:                         if (defbase == DB10) {base = 10; goto NUMVAL;}
  267:                 }
  268:                 goto HEXVAL;
  269:         }
  270: 
  271:         if (c == '\'') {       // hexadecimal number
  272:                 lptr--;
  273: HEXVAL:
  274:                 lptr++;
  275:                 tokenVal = getHexVal(&lptr);
  276:                 c = *lptr;
  277: NUMEXIT:
  278:                 // if the end of the numeric value is alphanumeric letter, then it is regarded as illegal numeric format.
  279:                 i = (isSym(c) || isNum(c)) ? tERNUM : tNUM;
  280:                 goto EXIT;
  281:         }
  282: 
  283:         if (isSym(c)) {                // symbol
  284:                 tokenStr = --lptr;
  285:                 for (i = 0; isSym(c) || isNum(c) || isExtSym(c); c = *++lptr) {
  286:                         // set to tokenSym[] in capital letters
  287:                         if (i < L_SYMBOL) {
  288:                                 if (c >= 'a' && c <= 'z') c -= 'a' - 'A';
  289:                                 tokenSym[i++] = c;
  290:                         }
  291:                 }
  292:                 // Fill the rest of tokenSym[] with space
  293:                 while (i < L_SYMBOL) tokenSym[i++] = ' ';
  294: 
  295:                 tokenLen = lptr - tokenStr;
  296:                 i = tSYM;
  297:                 goto EXIT;
  298:         }
  299:         // other: illegal character error
  300:         i = tERCH;
  301: EXIT:
  302:         return token = i;
  303: }
  304: /*
  305:         check for end of command
  306: */
  307: LOCAL   W isnotEOC(void)
  308: {
  309:         if (token <= tEOC) return 0;
  310:         return_er(E_PAR);
  311: }
  312: /*
  313:         check for separator (1)
  314: */
  315: LOCAL   W isDLM(void)
  316: {
  317:         if (token == tDLM) {getToken(0); return 1;}
  318:         return 0;
  319: }
  320: /*
  321:         check for separator (2)
  322: */
  323: LOCAL   W isnotDLM(void)
  324: {
  325:         if (isDLM()) return 0;
  326:         return_er(E_LESS);
  327: }
  328: /*
  329:         obtain numeric parameter (with performing + - * / operations)
  330: 
  331:         [+|-] {symbol|numeric value} [{+|-|* |/} {symbol|numeric value}].. {,|EOL}
  332: */
  333: LOCAL   W getNumber(W defbase, W *val)
  334: {
  335:         W      op, v;
  336:         UB     *p;
  337: 
  338:         // process leading + and -
  339:         if ((op = token) == tOPADD || op == tOPSUB) getToken(defbase);
  340: 
  341:         for (*val = 0; ;) {
  342:                 if (token == tSYM) {  // register name
  343:                         if ((v = searchRegister(tokenSym, 0)) >= 0) {
  344:                                 tokenVal = getRegister(v);
  345:                         } else {     // hexadecimal value
  346:                                 if (tokenSym[L_SYMBOL - 1] != ' ') break;
  347:                                 p = tokenSym;
  348:                                 tokenVal = getHexVal(&p);
  349:                                 if (*p != ' ') break;
  350:                         }
  351:                 } else if (token != tNUM) {
  352:                         return_er(E_LESS);   // non-numeric value
  353:                 }
  354: 
  355:                 // Performing + - * / operations
  356:                 if (op == tOPADD)     *val += tokenVal;
  357:                 else if (op == tOPSUB)        *val -= tokenVal;
  358:                 else if (op == tOPMUL)        *val *= tokenVal;
  359:                 else if (op == tOPDIV)        *val /= tokenVal;
  360:                 else                  *val = tokenVal;
  361: 
  362:                 // & operation
  363:                 while (getToken(defbase) == tOPIND) {
  364:                         if (readMem(*val, &v, 4, 4) != 4) return_er(E_MACV);
  365:                         *val = v;
  366:                 }
  367: 
  368:                 // extract the next item: if the next item is among "+ - * /" then continue processing
  369:                 if (token < tOPADD || token > tOPDIV) break;
  370:                 op = token;
  371:                 getToken(defbase);
  372:         }
  373:         if (token > tDLM) return_er(E_LESS);
  374:         return 0;
  375: }
  376: /*
  377:         obtain address range parameter
  378: 
  379:                 [start_addr][,{end_addr|#count}]
  380:                 cAddr = start_addr
  381:                 cLen  = count
  382: 
  383:         flg     0x01    start_addr cannot be omitted
  384:                 0x02    end_addr|#count (cannot be omitted)
  385: */
  386: LOCAL   W getAddrRange(W unit, W flg, W defsz)
  387: {
  388:         W      sizeflg;
  389: 
  390:         // start address
  391:         if (token > tDLM) {
  392:                 if (getNumber(0, &cAddr)) return E_LESS;
  393:         } else {
  394:                 if (flg & 0x01) return_er(E_LESS);    // cannot be omitted
  395:         }
  396: 
  397:         // align start address
  398:         cAddr = ALIGN_L(cAddr, unit);
  399: 
  400:         // end address
  401:         cLen = defsz;
  402:         if (token == tDLM) {
  403:                 sizeflg = 0;
  404:                 if (getToken(0) == tSIZ) {
  405:                         getToken(0);
  406:                         sizeflg++;
  407:                 }
  408:                 if (getNumber(0, (UW*)&cLen)) return E_LESS;
  409:                 if (sizeflg == 0) {   // end address: up to "+ size"
  410:                         if ((UW)cLen >= cAddr || (UW)cLen >= IMPLICIT_SIZE)
  411:                                 // truncate (using the size as unit)
  412:                                 cLen = ((W)((UW)cLen - cAddr) + unit) / unit;
  413:                 }
  414:                 cLen *= unit;
  415:         } else {
  416:                 if (flg & 0x02) return_er(E_LESS);    // cannot be omitted
  417:         }
  418: 
  419:         // validate address range
  420:         if (cLen <= 0 || cLen > MAX_RANGE)             return_er(E_RANGE);
  421:         if (((cLen + cAddr - 1) ^ cAddr) & 0x80000000) {
  422:                 cLen = (0x80000000 - (cAddr & 0x7fffffff)) / unit;
  423:                 if ((cLen *= unit) == 0) return_er(E_RANGE);
  424:         }
  425:         return 0;
  426: }
  427: /*
  428:         extract set data address
  429: 
  430:         {character string | numeric parameter}[, {character string | numeric parameter}]...EOC
  431: */
  432: LOCAL   W getSetData(UB *buf, W unit)
  433: {
  434:         W      n, k;
  435:         UW     num;
  436: 
  437:         for (n = 0; ;) {
  438:                 if (token == tSTR) {  // character string
  439:                         if (tokenLen == 0) return_er(E_EMPTY);
  440: 
  441:                         // Fill with 0 using 'unit' as data unit.
  442:                         k = ALIGN_U(tokenLen, unit);
  443:                         if (n + k > SETDT_SZ) return_er(E_LIMIT);
  444:                         memcpy(&buf[n], tokenStr, tokenLen);
  445:                         n += tokenLen;
  446:                         if ((k -= tokenLen) > 0) memset(&buf[n], 0, k);
  447:                         n += k;
  448:                         getToken(0);
  449:                 } else {              // numeric parameter
  450:                         if (n + unit > SETDT_SZ) return_er(E_LIMIT);
  451:                         if (getNumber(0, &num)) return E_LESS;
  452:                         switch (unit) {
  453:                         case 4:              *((UW*)&buf[n]) = (UW)num;  break;
  454:                         case 2:      *((UH*)&buf[n]) = (UH)num;  break;
  455:                         default:     buf[n] = (UB)num;
  456:                         }
  457:                         n += unit;
  458:                 }
  459:                 if (token <= tEOC) break;
  460:                 if (isnotDLM()) return E_LESS;
  461:         }
  462:         if (n == 0) return_er(E_EMPTY);
  463:         return n;      // data length
  464: }
  465: /*
  466:         memory read (with error message)
  467: */
  468: LOCAL   W reaMemory(UW addr, void *dt, W len, W unit)
  469: {
  470:         W      n;
  471: 
  472:         if ((n = readMem(addr, dt, len, unit)) == len) return 0;
  473:         DSP_F3(S,"ERR: Memory Read at H'", 08X,(addr+n), CH,'\n');
  474:         return -1;
  475: }
  476: /*
  477:         memory write (with error message)
  478: */
  479: LOCAL   W wriMemory(UW addr, void *dt, W len, W unit)
  480: {
  481:         W      n;
  482: 
  483:         if ((n = writeMem(addr, dt, len, unit)) == len) return 0;
  484:         DSP_F3(S,"ERR: Memory Write at H'", 08X,(addr+n), CH,'\n');
  485:         return -1;
  486: }
  487: /*
  488:         display memory content
  489: */
  490: LOCAL   void      dspMemory(void *p, W unit)
  491: {
  492:         switch (unit) {
  493:         case 4:                DSP_F2(08X,*((UW*)p), CH,' ');        break;
  494:         case 2:                DSP_F2(04X,*((UH*)p), CH,' ');        break;
  495:         default:       DSP_F2(02X,*((UB*)p), CH,' ');
  496:         }
  497: }
  498: /*
  499:         memroy dump command processing
  500: 
  501:         D  [start_addr][,{end_addr|#data_cnt}]
  502:         DB [start_addr][,{end_addr|#data_cnt}]
  503:         DH [start_addr][,{end_addr|#data_cnt}]
  504:         DW [start_addr][,{end_addr|#data_cnt}]
  505: */
  506: LOCAL   void      cmdDump(W unit)
  507: {
  508:         W      i, n, k;
  509:         UB     *cp, *ep;
  510: 
  511:         // extract address range
  512:         cAddr = dAddr;
  513:         if (getAddrRange(unit, 0x00, DEF_MEM_SIZE) || isnotEOC()) return;
  514: 
  515:         // dump memory content
  516:         ep = cp = wrkBuf;
  517:         for (dAddr = cAddr, i = 0; i < cLen;) {
  518:                 // display address
  519:                 if ((i % 16) == 0) DSP_F2(08X,dAddr, S,": ");
  520: 
  521:                 // obtain memory content
  522:                 if (cp >= ep) {
  523:                         if ((n = cLen - i) > WRKBUF_SZ) n = WRKBUF_SZ;
  524:                         k = readMem(dAddr, cp = wrkBuf, n, unit);
  525:                         if (n != k) {
  526:                                 errcode = E_MACV;
  527:                                 cLen = i + k;
  528:                         }
  529:                         ep = cp + k;
  530:                 }
  531:                 // display memory content
  532:                 if (i < cLen) {
  533:                         dspMemory(cp, unit);
  534:                         cp += unit;
  535:                         dAddr += unit;
  536:                         i += unit;
  537:                 }
  538:                 // display character
  539:                 if ((n = i % 16) == 0 || i >= cLen) {
  540:                         k = 16 - n;
  541:                         if (n) {     // move forward to where we start character dump
  542:                                 n = k / unit * (unit * 2 + 1);
  543:                                 while (n-- > 0)     DSP_CH(' ');
  544:                         }
  545:                         k = (i % 16) ? (i % 16) : 16;
  546:                         for (cp -= k; cAddr < dAddr; cAddr++) {
  547:                                 n = *cp++;
  548:                                 DSP_CH((n >= ' ' && n < 0x7f) ? n : '.');
  549:                         }
  550:                         DSP_LF;
  551:                 }
  552:                 if (checkAbort()) {DSP_LF; break;}
  553:         }
  554: }
  555: /*
  556:         memory update command processing
  557: 
  558:         M  [start_addr][,data]..
  559:         MB [start_addr][,data]..
  560:         MH [start_addr][,data]..
  561:         MW [start_addr][,data]..
  562: */
  563: LOCAL   void      cmdModify(W unit)
  564: {
  565:         W      n;
  566:         UB     buf[4];
  567:         UB     svbuf[L_LINE];
  568:         UB     *svlptr, svtoken;
  569:         UB     dt[SETDT_SZ];
  570: 
  571:         // start address
  572:         cAddr = mAddr;
  573:         if (token > tDLM && getNumber(0, &cAddr)) return;
  574: 
  575:         // align address
  576:         cAddr = ALIGN_L(cAddr, unit);
  577: 
  578:         if (token <= tEOC) {           // interactive processing
  579:                 // save command line
  580:                 memcpy(svbuf, lineBuf, L_LINE);
  581:                 svlptr = lptr;
  582:                 svtoken = token;
  583: 
  584:                 for (;;) {
  585:                         DSP_F2(08X,cAddr, S,": ");   // display address
  586:                         if (reaMemory(cAddr, buf, unit, unit)) break;
  587:                         dspMemory(buf, unit);                // display data
  588: 
  589:                         if (getLine("-> ") < 0) break;               // input set data
  590:                         if (getToken(0) == tEOD) break;              // end of data
  591:                         if (token <= tEOC) cAddr += unit;    // skip
  592:                         else if (token == tUP) cAddr -= unit;        // previous
  593:                         else if ((n = getSetData(dt, unit)) < 0) break;
  594:                         else {
  595:                                 if (wriMemory(cAddr, dt, n, unit)) break;
  596:                                 cAddr += n;
  597:                         }
  598:                 }
  599:                 // restore command line
  600:                 memcpy(lineBuf, svbuf, L_LINE);
  601:                 lptr = svlptr;
  602:                 token = svtoken;
  603:                 if (errcode == E_LESS) errcode = E_PAR;
  604: 
  605:         } else if (! isnotDLM()) {             // set data processing
  606:                 if ((n = getSetData(dt, unit)) > 0) {
  607:                         if (wriMemory(cAddr, dt, n, unit) == 0) cAddr += n;
  608:                 }
  609:         }
  610:         mAddr = cAddr;
  611: }
  612: /*
  613:         memory embedding command processing
  614: 
  615:         F  start_addr,{end_addr|#data_cnt}[,data]..
  616:         FB start_addr,{end_addr|#data_cnt}[,data]..
  617:         FH start_addr,{end_addr|#data_cnt}[,data]..
  618:         FW start_addr,{end_addr|#data_cnt}[,data]..
  619: */
  620: LOCAL   void      cmdFill(W unit)
  621: {
  622:         W      n;
  623:         UB     dt[SETDT_SZ];
  624: 
  625:         // extract address range
  626:         if (getAddrRange(unit, 0x03, DEF_MEM_SIZE)) return;
  627: 
  628:         // extract set data
  629:         if (token <= tEOC) {
  630:                 *((UW*)&dt[0]) = 0;   // 0 by default
  631:                 n = unit;
  632:         } else {
  633:                 if (isnotDLM()) return;
  634:                 if ((n = getSetData(dt, unit)) < 0) return;
  635:         }
  636: 
  637:         // embed set data into memory
  638:         if (n == unit) {       // fast processing
  639:                 wriMemory(cAddr, dt, cLen, unit | 0x10);
  640:         } else {               // ordinary mode
  641:                 for (; cLen > 0; cLen -= n, cAddr += n) {
  642:                         if (n > cLen) n = cLen;
  643:                         if (wriMemory(cAddr, dt, n, unit)) break;
  644:                 }
  645:         }
  646: }
  647: /*
  648:         memory search command processing
  649: 
  650:         SC  start_addr,{end_addr|#data_cnt},search_data..
  651:         SCB start_addr,{end_addr|#data_cnt},search_data..
  652:         SCH start_addr,{end_addr|#data_cnt},search_data..
  653:         SCW start_addr,{end_addr|#data_cnt},search_data..
  654: */
  655: LOCAL   void      cmdSearch(W unit)
  656: {
  657:         W      n, len, cnt, ofs;
  658:         UB     *cp, *ep;
  659:         UB     dt[SETDT_SZ];
  660: 
  661:         // extract address range
  662:         if (getAddrRange(unit, 0x01, DEF_MEM_SIZE) || isnotDLM()) return;
  663: 
  664:         // extract search data
  665:         if ((len = getSetData(dt, unit)) < 0) return;
  666: 
  667:         ep = cp = wrkBuf;
  668:         for (ofs = cnt = 0; ; ) {
  669:                 // obtain memory content
  670:                 if (cp >= ep) {
  671:                         if ((n = WRKBUF_SZ - ofs) > cLen) n = cLen;
  672:                         if (ofs + n < len) break;    // end
  673:                         if (reaMemory(cAddr, &wrkBuf[ofs], n, unit)) break;
  674:                         cAddr += n;
  675:                         cLen -= n;
  676:                         ep = (cp = wrkBuf) + ofs + n;
  677:                 }
  678:                 // check if the leading byte matches
  679:                 for ( ; cp < ep && *cp != dt[0]; cp += unit);
  680:                 if ((ofs = ep - cp) < len) {
  681:                         // if enough data is not there, move to the beginning of buffer.
  682:                         if (ofs > 0) memcpy(wrkBuf, ep = cp, ofs);
  683:                         continue;
  684:                 }
  685:                 // check for the matching of whole data
  686:                 if (memcmp(cp, dt, len) == 0) {
  687:                         if (++cnt > MAX_DSP_CNT) {
  688:                                 DSP_S("..More..\n");
  689:                                 break;
  690:                         }
  691:                         DSP_F2(08X,(cAddr - (ep - cp)), S,":\n");
  692:                 }
  693:                 // next
  694:                 cp += unit;
  695:                 ofs = 0;
  696:                 if (checkAbort()) break;
  697:         }
  698: }
  699: /*
  700:         memory comparison / move command processing
  701: 
  702:         CMP start_addr,{end_addr|#data_cnt},target_addr
  703:         MOV start_addr,{end_addr|#data_cnt},target_addr
  704: */
  705: LOCAL   void      cmdCmpMov(W mov)
  706: {
  707:         UW     dst;
  708:         W      i, n, cnt;
  709: #define BFSZ    (WRKBUF_SZ / 2)
  710: 
  711:         // extract address range
  712:         if (getAddrRange(1, 0x01, DEF_MEM_SIZE) || isnotDLM()) return;
  713: 
  714:         // transfer / compare target
  715:         if (getNumber(0, &dst) || isnotEOC()) return;
  716: 
  717:         if (mov) {     // memory transfer
  718:                 for (; (n = cLen) > 0 && checkAbort() == 0;
  719:                                         cAddr += n, dst += n, cLen -= n) {
  720:                         if (n > WRKBUF_SZ) n = WRKBUF_SZ;
  721:                         if (reaMemory(cAddr, wrkBuf, n, 1)) break;
  722:                         if (wriMemory(dst, wrkBuf, n, 1)) break;
  723:                 }
  724: 
  725:         } else {       // memory comparison
  726:                 for (cnt = 0; (n = cLen) > 0 && checkAbort() == 0;
  727:                                         cAddr += n, dst += n, cLen -= n) {
  728:                         if (n > BFSZ) n = BFSZ;
  729:                         if (reaMemory(cAddr, wrkBuf, n, 1)) break;
  730:                         if (reaMemory(dst, &wrkBuf[BFSZ], n, 1)) break;
  731:                         if (memcmp(wrkBuf, &wrkBuf[BFSZ], n) == 0) continue;
  732:                         for (i = 0; i < n; i++) {
  733:                                 if (wrkBuf[i] == wrkBuf[BFSZ + i]) continue;
  734:                                 if (++cnt > MAX_DSP_CNT) {
  735:                                         DSP_S("..More..\n");
  736:                                         cLen = 0;  // terminate
  737:                                         break;
  738:                                 }
  739:                                 DSP_F4(08X,(cAddr + i), S,": ",
  740:                                        02X,wrkBuf[i], S," -> ");
  741:                                 DSP_F4(08X,(dst + i), S,": ",
  742:                                        02X,(wrkBuf[BFSZ + i]), CH,'\n');
  743:                         }
  744:                 }
  745:         }
  746: }
  747: /*
  748:         I/O port input and output command processing
  749: 
  750:         IB/IH/IW       port
  751:         OB/OH/OW       port, data
  752: */
  753: LOCAL   void      cmdIO(W unit)
  754: {
  755:         UW     port, data;
  756:         UB     *dir;
  757: 
  758:         // extract port number
  759:         if (getNumber(0, &port)) return;
  760: 
  761:         if (unit & 0x10) {     // output command
  762:                 if (!isDLM()) er_return(E_LESS);
  763:                 if (getNumber(0, &data) || isnotEOC()) return;
  764:                 if (writeIO(port, data, unit &= 0x0f) == 0) er_return(E_MACV);
  765:                 dir = "<--";
  766:         } else {               // input command
  767:                 if (isnotEOC()) return;
  768:                 if (readIO(port, &data, unit) == 0) er_return(E_MACV);
  769:                 dir = "-->";
  770:         }
  771:         // display result
  772:         DSP_F2(S,"Port ", 08X,port);
  773:         switch (unit) {
  774:         case 4:        DSP_F5(S,":W ", S,dir, CH,' ', 08X,(UW)data, CH,'\n');
  775:                 break;
  776:         case 2:        DSP_F5(S,":H ", S,dir, CH,' ', 04X,(UH)data, CH,'\n');
  777:                 break;
  778:         default:DSP_F5(S,":B ", S,dir, CH,' ', 02X,(UB)data, CH,'\n');
  779:                 break;
  780:         }
  781: }
  782: /*
  783:         disasseble command processing
  784: 
  785:         DA [start_addr][,steps]
  786: */
  787: LOCAL   void      cmdDisasm(void)
  788: {
  789:         er_return(E_NOSPT);
  790: }
  791: /*
  792:         display / set register command processing
  793: 
  794:         R [register_name[,data]]
  795: */
  796: LOCAL   void      cmdRegister(void)
  797: {
  798:         W      rno;
  799:         UW     num;
  800: 
  801:         if (token <= tEOC) {   // ordinary register dump
  802:                 dispRegister(-1);
  803: 
  804:         } else {               // extract register name
  805:                 if (token != tSYM || (rno = searchRegister(tokenSym, 1)) < 0)
  806:                         er_return(E_ILREG);
  807: 
  808:                 if (getToken(0) <= tEOC) {    // display register
  809:                         dispRegister(rno);
  810: 
  811:                 } else if (!isnotDLM() && !getNumber(0, &num)) {      // set register
  812:                         if (!isnotEOC())
  813:                                 er_return(setRegister(rno, num));
  814:                 }
  815: 
  816: 
  817:         }
  818: }
  819: /*
  820:         execute / trace command processing
  821: 
  822:         G      [start_addr][,end_addr]
  823:         S/N    [start_addr][,steps]
  824: */
  825: LOCAL   void      cmdGoTrace(W trace)
  826: {
  827:         UW     pc, par;
  828: 
  829:         // extract execution address
  830:         pc = getCurPC();
  831:         if (token > tDLM && getNumber(0, &pc)) return;
  832:         if (invalidPC(pc)) er_return(E_PC);
  833: 
  834:         // extract end address or number of steps
  835:         par = 0;
  836:         if (isDLM()) {
  837:                 if (getNumber(0, &par)) return;
  838:                 if (trace == 0 && invalidPC(par)) er_return(E_MACV);
  839:         }
  840:         if (isnotEOC()) return;
  841: 
  842:         if (trace && par <= 0) par = 1;                // number of steps
  843: 
  844:         //execute program
  845:         errcode = goTrace(trace, pc, par);
  846:         if (errcode >= E_OK) errcode = CMD_FINISH;     //command process termination
  847: }
  848: /*
  849:         display / set breakpoint command processing
  850: 
  851:         B [break_addr[,break_attr][,commands]]
  852: */
  853: LOCAL   void      cmdBreak(VOID)
  854: {
  855:         UW     addr;
  856:         W      atr, cmdlen;
  857:         UB     *cmd;
  858: 
  859:         if (token <= tEOC) {    // display breakpoint
  860:                 dspBreak();
  861:                 return;
  862:         }
  863: 
  864:         // extract breakpoint address
  865:         if (getNumber(0, &addr)) return;
  866: 
  867:         // extract break attribute and command
  868:         atr = cmdlen = 0;
  869:         cmd = NULL;
  870:         while (token == tDLM) {
  871:                 // "+:" are handled as symbols
  872:                 symExt[0] = '+'; symExt[1] = ':';
  873:                 getToken(0);
  874:                 symExt[0] = symExt[1] = '\0';
  875:                 if (token == tSYM) {
  876:                         if (atr) break;
  877:                         if ((atr = getBreakAtr(tokenSym)) < 0)
  878:                                 er_return(E_BPATR);
  879:                 } else if (token == tSTR) {
  880:                         if (cmdlen) break;
  881:                         if ((cmdlen = tokenLen) > L_BPCMD) er_return(E_BPCMD);
  882:                         cmd = tokenStr;
  883:                 }
  884:                 getToken(0);
  885:         }
  886: 
  887:         //set breakpoint
  888:         if (! isnotEOC()) {
  889:                 if ((atr = setBreak(addr, atr, cmd, cmdlen))) er_return(atr);
  890:         }
  891: }
  892: /*
  893:         clear breakpoint command processing
  894: 
  895:         BC [break_addr][,break_addr]..
  896: */
  897: LOCAL   void      cmdBrkClr(void)
  898: {
  899:         UW     addr;
  900: 
  901:         if (token <= tEOC) {
  902:                 clearBreak(0);        // clear all
  903:         } else {
  904:                 do {  // clear individual breakpoint
  905:                         if (getNumber(0, &addr)) return;
  906:                         if (clearBreak(addr) < 0) er_return(E_BPUDF);
  907:                 } while (isDLM());
  908:                 isnotEOC();
  909:         }
  910: }
  911: /*
  912:         download command processing
  913: 
  914:         LO protocol[,loading_addr]
  915: */
  916: LOCAL   void      cmdLoad(void)
  917: {
  918:         W      i, par;
  919:         UW     addr;
  920: LOCAL   const     struct {
  921:         UB     nm[2];
  922:         UH     par;
  923: } proto[] = {
  924:         {"S ", P_TEXT | P_SFORM},
  925:         {"XS", P_XMODEM | P_SFORM},
  926:         {"XM", P_XMODEM | P_MEMIMG},
  927:         {"  ", 0x00}
  928: };
  929: 
  930:         // extract protocol
  931:         if (token != tSYM) er_return(E_LESS);
  932: 
  933:         par = 0;
  934:         if (tokenSym[2] == ' ')  {
  935:                 for (i = 0; proto[i].par != 0; i++) {
  936:                         if (*((UH*)tokenSym) == *((UH*)proto[i].nm)) {
  937:                                 par = proto[i].par;
  938:                                 break;
  939:                         }
  940:                 }
  941:         }
  942:         if (par == 0) er_return(E_PROTO);
  943: 
  944:         // extract start address
  945:         getToken(0);
  946:         if (isDLM()) {
  947:                 if (getNumber(0, &addr)) return;
  948:         } else {
  949:                 addr = 0;
  950:                 if (par & P_MEMIMG) er_return(E_NOADDR);
  951:         }
  952:         if (isnotEOC()) return;
  953: 
  954:         // execute loading
  955:         errcode = doLoading(par, addr, NULL);
  956: }
  957: /*
  958:         backtrace command processing
  959: 
  960:         BTR
  961: */
  962: LOCAL   void      cmdBackTrace(void)
  963: {
  964:         er_return(E_NOSPT);
  965: }
  966: /*
  967:         disk command processing
  968: 
  969:         RD device, sblk, nblk, addr
  970:         WD device, sblk, nblk, addr
  971:         ID device
  972:         BD [device]
  973: */
  974: LOCAL   void      cmdDisk(W kind)
  975: {
  976:         W      i;
  977:         UW     par[3], blksz, nblks;
  978:         UB     c, devnm[L_DEVNM + 1];
  979: 
  980:         // extract device name
  981:         if (token <= tEOC) {
  982:                 if (kind != 3) er_return(E_LESS);
  983:                 devnm[0] = '\0';
  984:         } else {
  985:                 if (token != tSYM || tokenLen > L_DEVNM) er_return(E_LESS);
  986:                 // device names are to be given in lower case letters
  987:                 for (i = 0; i < tokenLen; i++) {
  988:                         c = tokenSym[i];
  989:                         if (c >= 'A' && c <= 'Z') c += 'a' - 'A';
  990:                         devnm[i] = c;
  991:                 }
  992:                 devnm[i] = '\0';
  993:                 getToken(0);
  994:         }
  995: 
  996:         // extract parameters
  997:         if (kind <= 1) {
  998:                 for (i = 0; i < 3; i++) {
  999:                         if (isnotDLM()) return;
 1000:                         if (getNumber(0, &par[i])) return;
 1001:                 }
 1002:         }
 1003:         if (isnotEOC()) return;
 1004: 
 1005:         switch(kind) {
 1006:         case 0:                // ReadDisk
 1007:         case 1:                // WriteDisk
 1008:                 errcode = rwDisk(devnm, par[0], par[1], (void*)par[2], kind);
 1009:                 break;
 1010:         case 2:                // InfoDisk
 1011:                 errcode = infoDisk(devnm, &blksz, &nblks);
 1012:                 if (errcode >= E_OK) {
 1013:                         DSP_S(devnm);
 1014:                         DSP_F5(S,": Bytes/block: ", D,blksz,
 1015:                                S," Total blocks: ", D,nblks, CH,'\n');
 1016:                 }
 1017:                 break;
 1018:         case 3:                // BootDisk
 1019:                 errcode = bootDisk(( devnm[0] == '\0' )? NULL: devnm);
 1020:                 if (errcode >= E_OK) errcode = CMD_FINISH;    // Fin
 1021:                 break;
 1022:         }
 1023: }
 1024: /*
 1025:         exit command processing
 1026: 
 1027:         EX     [par]
 1028: */
 1029: LOCAL   void      cmdExit(void)
 1030: {
 1031:         W      par;
 1032: 
 1033:         // extract parameters
 1034:         if (token <= tDLM) par = 0;
 1035:         else if (getNumber(0, &par)) return;
 1036: 
 1037:         DSP_S((par < 0) ? "** System Reset\n" : "** System Power Off\n");
 1038:         waitMsec(100); /* give extra time for draining the remaining output */
 1039: 
 1040:         sysExit(par);          // system reset or power off (never returnes)
 1041: }
 1042: /*
 1043:         forcible kill process command processing
 1044: 
 1045:         KILL
 1046: */
 1047: LOCAL   void      cmdKill(void)
 1048: {
 1049:         if (isnotEOC()) return;
 1050:         if (isKillValid() == 0) {
 1051:                 killProcReq = 1;
 1052:                 errcode = CMD_FINISH;
 1053:         }
 1054: }
 1055: /*
 1056:         FROM write command processing
 1057: 
 1058:         WROM
 1059: */
 1060: LOCAL   void      cmdWrom(void)
 1061: {
 1062:         UW     addr, data;
 1063:         W      nsec;
 1064: 
 1065:         // extract parameters
 1066:         if (getNumber(0, &addr)) return;
 1067:         if (isnotDLM() || getNumber(0, &data)) return;
 1068:         if (isnotDLM() || getNumber(0, &nsec)) return;
 1069:         if (isnotEOC()) return;
 1070:         errcode = writeFrom(addr, data, nsec, 1);
 1071: }
 1072: /*
 1073:         FLASH ROM load command processing
 1074: 
 1075:         FLLO [attr]
 1076: */
 1077: LOCAL   void      cmdFlashLoad(void)
 1078: {
 1079:         W      i, proto, mode;
 1080:         UW     addr[3];
 1081: 
 1082:         proto = P_TEXT | P_SFORM;
 1083:         mode = 0;
 1084: 
 1085:         // extract attributes
 1086:         if (token > tEOC) {
 1087:                 if (token != tSYM) er_return(E_PAR);
 1088:                 for (i = 0; i < L_SYMBOL; i++) {
 1089:                         switch(tokenSym[i]) {
 1090:                         case 'X':    proto = P_XMODEM | P_SFORM;        break;
 1091:                         case 'E':    mode = 1;                  break;
 1092:                         case ' ':    i = L_SYMBOL;                      break;
 1093:                         default:     er_return(E_PAR);
 1094:                         }
 1095:                 }
 1096:                 getToken(0);
 1097:                 if (isnotEOC()) return;
 1098:         }
 1099: 
 1100:         // execute loading
 1101:         setupFlashLoad(0, addr);
 1102:         i = addr[1] - addr[0] + 1;
 1103:         if (mode) {
 1104:                 DSP_S("Fill Loading RAM Area with 0xFF\n");
 1105:                 memset((void*)addr[0], 0xFF, i);
 1106:         } else {
 1107:                 DSP_S("Copy Flash ROM Image to RAM Area\n");
 1108:                 memcpy((void*)addr[0], (void*)(addr[0] - addr[2]), i);
 1109:         }
 1110:         DSP_S("> Load S-Format Data of Flash ROM\n");
 1111:         errcode = doLoading(proto, 0, addr);
 1112:         if (errcode < 0) return;
 1113: 
 1114:         // FLASH ROM write
 1115:         setupFlashLoad(-1, addr);
 1116:         DSP_F5(S,"Writing Flash ROM at ", 08X,addr[0],
 1117:                S," [", D,addr[2], S," blks] ... wait\n");
 1118:         errcode = writeFrom(addr[0], addr[1], addr[2], -1);
 1119: }
 1120: /*
 1121:         command table
 1122: */
 1123: typedef struct {
 1124:         UB             fnm[12];   // full command name
 1125:         UB             snm[4];            // abbreviated command name
 1126:         FP             func;              // processing function
 1127:         W              para;               // parameter information and other
 1128:         const HELP     *help;              // help message
 1129: } CMDTAB;
 1130: 
 1131: #define IGN_TRACE       0x1000
 1132: 
 1133: LOCAL   void      cmdHelp(void);
 1134: 
 1135: LOCAL   const     CMDTAB      cmdTab[] = {
 1136:         {"DUMP        ","D   ",        cmdDump,       1,            &helpD      },
 1137:         {"DUMPBYTE    ","DB  ",        cmdDump,       1,            &helpDB     },
 1138:         {"DUMPHALF    ","DH  ",        cmdDump,       2,            &helpDH     },
 1139:         {"DUMPWORD    ","DW  ",        cmdDump,       4,            &helpDW     },
 1140:         {"MODIFY      ","M   ",        cmdModify,     1,          &helpM    },
 1141:         {"MODIFYBYTE  ","MB  ",        cmdModify,     1,          &helpMB   },
 1142:         {"MODIFYHALF  ","MH  ",        cmdModify,     2,          &helpMH   },
 1143:         {"MODIFYWORD  ","MW  ",        cmdModify,     4,          &helpMW   },
 1144:         {"FILL        ","F   ",        cmdFill,       1,            &helpF      },
 1145:         {"FILLBYTE    ","FB  ",        cmdFill,       1,            &helpFB     },
 1146:         {"FILLHALF    ","FH  ",        cmdFill,       2,            &helpFH     },
 1147:         {"FILLWORD    ","FW  ",        cmdFill,       4,            &helpFW     },
 1148:         {"SEARCH      ","SC  ",        cmdSearch,     1,          &helpSC   },
 1149:         {"SEARCHBYTE  ","SCB ",        cmdSearch,     1,          &helpSCB  },
 1150:         {"SEARCHHALF  ","SCH ",        cmdSearch,     2,          &helpSCH  },
 1151:         {"SEARCHWORD  ","SCW ",        cmdSearch,     4,          &helpSCW  },
 1152:         {"COMPARE     ","CMP ",        cmdCmpMov,     0,          &helpCMP  },
 1153:         {"MOVE        ","MOV ",        cmdCmpMov,     1,          &helpMOV  },
 1154:         {"INPUTBYTE   ","IB  ",        cmdIO,         1,             &helpIB      },
 1155:         {"INPUTHALF   ","IH  ",        cmdIO,         2,             &helpIH      },
 1156:         {"INPUTWORD   ","IW  ",        cmdIO,         4,             &helpIW      },
 1157:         {"OUTPUTBYTE  ","OB  ",        cmdIO,         0x11,          &helpOB   },
 1158:         {"OUTPUTHALF  ","OH  ",        cmdIO,         0x12,          &helpOH   },
 1159:         {"OUTPUTWORD  ","OW  ",        cmdIO,         0x14,          &helpOW   },
 1160:         {"DISASSEMBLE ","DA  ",        cmdDisasm,     0,          &helpDA   },
 1161:         {"REGISTER    ","R   ",        cmdRegister,   0,                &helpR          },
 1162:         {"BREAKPOINT  ","B   ",        cmdBreak,      0,           &helpB     },
 1163:         {"BREAKCLEAR  ","BC  ",        cmdBrkClr,     0,          &helpBC   },
 1164:         {"GO          ","G   ",        cmdGoTrace,    0 | IGN_TRACE,     &helpG        },
 1165:         {"STEP        ","S   ",        cmdGoTrace,    1 | IGN_TRACE,     &helpS        },
 1166:         {"NEXT        ","N   ",        cmdGoTrace,    2 | IGN_TRACE,     &helpN        },
 1167:         {"BACKTRACE   ","BTR ",        cmdBackTrace,  0,               &helpBTR  },
 1168:         {"LOAD        ","LO  ",        cmdLoad,       0,            &helpLO     },
 1169:         {"READDISK    ","RD  ",        cmdDisk,       0,            &helpRD     },
 1170:         {"WRITEDISK   ","WD  ",        cmdDisk,       1,            &helpWD     },
 1171:         {"INFODISK    ","ID  ",        cmdDisk,       2,            &helpID     },
 1172:         {"BOOTDISK    ","BD  ",        cmdDisk,       3,            &helpBD     },
 1173:         {"KILL        ","KILL",        cmdKill,       0,            &helpKILL },
 1174:         {"WRITEROM    ","WROM",        cmdWrom,       0,            &helpWROM },
 1175:         {"FLASHLOAD   ","FLLO",        cmdFlashLoad,  0,               &helpFLLO },
 1176:         {"HELP        ","H   ",        cmdHelp,       0,            &helpH      },
 1177:         {"HELP        ","?   ",        cmdHelp,       0,            &helpH      },
 1178:         {"EXIT        ","EX  ",        cmdExit,       0,            &helpEX     },
 1179:         { } /* end */
 1180: };
 1181: /*
 1182:         searching command
 1183: */
 1184: LOCAL   W searchCommand(void)
 1185: {
 1186:         W      i;
 1187: 
 1188:         if (token == tSYM && tokenSym[12] == ' ') {
 1189:                 for (i = 0; cmdTab[i].func != NULL; i++) {
 1190:                         if (memcmp(cmdTab[i].fnm, tokenSym, 12) == 0 ||
 1191:                                 (tokenSym[4] == ' ' &&
 1192:                                 *((UW*)cmdTab[i].snm) == *((UW*)tokenSym)) )
 1193:                                 return i;
 1194:                 }
 1195:         }
 1196:         return E_CMD;
 1197: }
 1198: /*
 1199:         help command pcrocessing
 1200: 
 1201:         H(?) [command]
 1202: */
 1203: LOCAL   void      cmdHelp(void)
 1204: {
 1205:         W      i;
 1206: 
 1207:         i = searchCommand();
 1208:         printHelp(( i < 0 )? &helpALL: cmdTab[i].help);
 1209: }
 1210: /*
 1211:         command interpreter
 1212: 
 1213:         cmd : initial command line (if NULL : none)
 1214:         fin : 0 = continue, 1 = finish (command execution)
 1215:               < 0 : trace command execution
 1216: */
 1217: EXPORT  void     procCommand(UB *cmd, W fin)
 1218: {
 1219:         W      i, par;
 1220: 
 1221:         // initialize command input
 1222:         if (cmd) {
 1223:                 strcpy(lptr = lineBuf, cmd);
 1224:                 token = tEOC;
 1225:         } else {
 1226:                 token = tEOL;
 1227:                 fin = 0;
 1228:         }
 1229: 
 1230:         // set DA address to PC
 1231:         daAddr = getCurPC();
 1232: 
 1233:         for (;;) {
 1234:                 // skip the remainder of the previous command
 1235:                 while (token > tEOC) getToken(0);
 1236: 
 1237:                 // input a command line
 1238:                 if (token == tEOL) {
 1239:                         if (fin) break;              // end
 1240:                         if (getLine(PROMPT) <= 0) continue;
 1241:                 }
 1242: 
 1243:                 // skip comment
 1244:                 skipSpace();
 1245:                 if (*lptr == '*') {
 1246:                         getToken(0);
 1247:                         continue;
 1248:                 }
 1249:                 // extract command
 1250:                 if (getToken(0) <= tEOC) continue;    // skip empty line
 1251: 
 1252:                 // searching command
 1253:                 errcode = errinfo = 0;
 1254:                 if ((i = searchCommand()) < 0) {
 1255:                         errcode = E_CMD;
 1256:                 } else {
 1257:                         if (checkAbort()) continue;
 1258:                         par = cmdTab[i].para;
 1259: 
 1260:                         // if there is an initial command, the execution command is ignored
 1261:                         if (fin < 0 && (par & IGN_TRACE)) continue;
 1262: 
 1263:                         // read-ahead of parameters
 1264:                         getToken(0);
 1265: 
 1266:                         // command execution
 1267:                         (*(cmdTab[i].func))(par & 0xff);
 1268:                 }
 1269:                 if (errcode == CMD_FINISH) break;     // finish
 1270: 
 1271:                 // display error
 1272:                 if (errcode < 0) dspError();
 1273:         }
 1274: }