gonzui


Format: Advanced Search

tkernel_2/monitor/cmdsvc/src/load.cbare sourcepermlink (0.04 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 TRON Forum(http://www.tron.org/) at 2015/06/01.
   11:  *
   12:  *----------------------------------------------------------------------
   13:  */
   14: 
   15: /*
   16:  *      load.c
   17:  *
   18:  *       load processing
   19:  */
   20: 
   21: #include "cmdsvc.h"
   22: 
   23: LOCAL   UW        s_addr;                        // start address
   24: LOCAL   UW        e_addr;                        // end address + 1
   25: LOCAL   UW        offset;                        // address offset
   26: LOCAL   UW        loaddr;                        // address lower limit
   27: LOCAL   UW        hiaddr;                        // address upper limit
   28: LOCAL   W blkno;                  // block number
   29: LOCAL   W blkptr;                 // read pointer
   30: #define XBLK_SZ 1024                    // XMODEM block size (extended)
   31: #define BLK_SZ  128                      // XMODEM block size
   32: #define blkbuf  wrkBuf                   // block buffer
   33: LOCAL   W blksz;                  // block size
   34: 
   35: LOCAL   FUNCP     readFn;                     // read function
   36: 
   37: #define inputByte(tmo)  getSIO(tmo)      // input one byte
   38: #define outputByte(c)   putSIO(c) // output one byte
   39: 
   40: // XMODEM control codes
   41: #define SOH             (0x01)
   42: #define STX             (0x02)
   43: #define EOT             (0x04)
   44: #define ACK             (0x06)
   45: #define NAK             (0x15)
   46: #define CAN             (0x18)
   47: #define CTLC            ('C' - '@')
   48: #define CTLZ            ('Z' - '@')
   49: 
   50: /* XMODEM time out specification
   51:  *       wait for SOH : 10 seconds / 10 retries
   52:  *       timeout between two characters : 1 seconds
   53:  *
   54:  * how to cope with communication software (mainly for TeraTerm) that does not start automatic transfer
   55:  *     (this falls outside XMODEM specification)
   56:  *      Since the timeout value for SOH is 10 seconds, the initial transfer always seem to wait for 10 seconds.
   57:  *       The initial timeout for SOH is set to 3 seconds (only for the very first transfer.)
   58:  */
   59: #define IDLE_TMO        ( 1 * 1000)    // idle wait(milliseconds)
   60: #define RECV_TMO        ( 1 * 1000)    // timeout for data input (milliseconds)
   61: #define SOH_TMO         (10 * 1000)    // timeout for SOH input (milliseconds)
   62: #define SOH1_TMO        ( 3 * 1000)    // timeout for the initial SOH input (milliseconds)
   63: #define MAX_RETRY       10            // maximum number of retries
   64: 
   65: /*
   66:         skip until there is no more input
   67: */
   68: LOCAL   void      purgeInput(void)
   69: {
   70:         while (inputByte(IDLE_TMO) >= 0);
   71: }
   72: /*
   73:         asynchronous read processing (without any protocol)
   74: */
   75: LOCAL   W textRead(void)
   76: {
   77:         W      c;
   78: 
   79:         while ((c = inputByte(0)) < 0);
   80:         return (c == CTLC || c == CAN) ? E_CANCEL : c;
   81: }
   82: /*
   83:         XMODEM read processing
   84: */
   85: LOCAL   W xmodemRead(void)
   86: {
   87:         W      i, c, ctlch;
   88:         UB     cksum;
   89: 
   90:         if (blkptr < blksz) return blkbuf[blkptr++];
   91: 
   92:         c = 0;
   93:         ctlch = ACK;
   94:         if (blkno++ == 0) {
   95:                 /* only for the initial packet transfer */
   96:                 outputByte(NAK);
   97:                 c = inputByte(SOH1_TMO);
   98:                 ctlch = -1;
   99:         }
  100: 
  101:         for (;;) {
  102:                 // receiving block
  103:                 for (i = 0;;) {
  104:                         if (ctlch >= 0) {
  105:                                 // ack/beginning character is transmitted
  106:                                 outputByte(ctlch);
  107: 
  108:                                 // leading letter in the ack is extracted
  109:                                 c = inputByte(SOH_TMO);
  110:                         }
  111:                         ctlch = NAK;
  112:                         if (c == SOH) {blksz = BLK_SZ;       break;}
  113:                         if (c == STX) {blksz = XBLK_SZ; break;}
  114:                         if (c == CAN || c == CTLC) { // cancel transfer
  115:                                 // Is CAN followed by another CAN?
  116:                                 c = inputByte(IDLE_TMO);
  117:                                 if (c < 0 || c == CAN || c == CTLC)
  118:                                                         return E_CANCEL;
  119:                         } else if (c == EOT) {       // end of transmission
  120:                                 outputByte(ACK);
  121:                                 return E_END;
  122:                         }
  123:                         purgeInput();        // skip data
  124:                         if (++i >= MAX_RETRY) return E_XMODEM;
  125:                 }
  126: 
  127:                 // read a block number & check
  128:                 if ((i = inputByte(RECV_TMO)) < 0) continue;
  129:                 if ((c = inputByte(RECV_TMO)) < 0) continue;
  130:                 if (i + c != 0xff) continue;
  131: 
  132:                 if (i != (blkno & 0xff)) {
  133:                         if (i != ((blkno - 1) & 0xff)) return E_XMODEM;
  134:                         // skip if the previous block is read
  135:                         ctlch = ACK;
  136:                 }
  137: 
  138:                 // read the block itself
  139:                 for (cksum = 0, i = 0; i < blksz; i++) {
  140:                         if ((c = inputByte(RECV_TMO)) < 0) break;
  141:                         cksum += (blkbuf[i] = c);
  142:                 }
  143:                 if (c < 0) continue;
  144: 
  145:                 // validate checksum
  146:                 if (inputByte(RECV_TMO) == cksum && ctlch != ACK) break;
  147:         }
  148:         blkptr = 0;
  149:         return blkbuf[blkptr++];
  150: }
  151: /*
  152:         XMODEM termination processing
  153: */
  154: LOCAL   void      xmodemEnd(W er)
  155: {
  156:         // finish XMODEM protocol
  157:         while (er >= 0) er = xmodemRead();
  158: 
  159:         if (er != E_END && er != E_CANCEL) {
  160:                 purgeInput();         // wait until there is no more data
  161:                 outputByte(CAN);      // transmite two (or more) consecutive CANs
  162:                 outputByte(CAN);
  163:                 outputByte(CAN);
  164:         }
  165: }
  166: /*
  167:         load memory image
  168: */
  169: LOCAL   W loadImage(void)
  170: {
  171:         W      i, c;
  172:         UB     buf[512];
  173: 
  174:         for (i = 0;;) {
  175:                 if ((c = (*readFn)()) >= 0) buf[i++] = c;
  176:                 if (i < sizeof(buf) && c >= 0) continue;
  177:                 if (i > 0) {
  178:                         if (e_addr < loaddr ||
  179:                                 e_addr - 1 > hiaddr - i) return E_RANGE;
  180:                         if (writeMem(e_addr, buf, i, 1) != i) return E_MACV;
  181:                         e_addr += i;
  182:                         i = 0;
  183:                 }
  184:                 if (c < 0) return c;
  185:         }
  186: }
  187: /*
  188:         read a hexadecimal character
  189: */
  190: LOCAL   W readHex(void)
  191: {
  192:         W      c;
  193: 
  194:         if ((c = (*readFn)()) < 0)     return c;
  195:         if (c >= '0' && c <= '9')      return c - '0';
  196:         if (c >= 'A' && c <= 'F')      return c - 'A' + 10;
  197:         if (c >= 'a' && c <= 'f')      return c - 'a' + 10;
  198:         return E_LOAD;
  199: }
  200: /*
  201:         load S format data
  202: */
  203: LOCAL   W loadSform(void)
  204: {
  205:         W      i, c, bcnt, v, v1, dcnt, rtype;
  206:         UW     addr, a_addr;
  207:         UB     cksum, buf[512];
  208: 
  209:         a_addr = s_addr;               // real address
  210:         s_addr = 0xffffffff;           // highest load address
  211:         e_addr = 0;                    // lowest load address
  212: 
  213:         for (;;) {
  214:                 if ((c = (*readFn)()) < 0) return c;
  215: 
  216:                 if (c != 'S') {
  217:                         if (c == CTLZ) break;        // end
  218:                         continue;
  219:                 }
  220: 
  221:                 if ((c = (*readFn)()) < 0) return c;
  222:                 switch(c) {
  223:                 case '0':     // header
  224:                                 rtype = 0;          break;
  225:                 case '1':     // 2 byte address data
  226:                 case '2':     // 3 byte address data
  227:                 case '3':     // 4 byte address data
  228:                                 rtype = c - '0' + 2;        break;
  229:                 case '7':     // 4 byte address termination
  230:                 case '8':     // 3 byte address termination
  231:                 case '9':     // 2 byte address termination
  232:                                 rtype = -1;         break;
  233:                 default:      return E_LOADFMT;
  234:                 }
  235: 
  236:                 for (cksum = bcnt = addr = dcnt = i = 0;; i++) {
  237:                         if ((v1 = readHex()) < 0) return v1;
  238:                         if ((v = readHex()) < 0)  return v;
  239:                         cksum += (v += (v1 << 4));
  240: 
  241:                         if (i == 0) {                // byte counts
  242:                                 if ((bcnt = v - 1) < 0) return E_LOAD;
  243:                                 addr = 0;
  244:                                 continue;
  245:                         }
  246:                         if (i > bcnt) {              // checksum
  247:                                 if (cksum != 0xff) return E_LOAD;
  248:                                 break;
  249:                         }
  250:                         if (rtype <= 0) continue;
  251: 
  252:                         if (i < rtype) {     // load address
  253:                                 addr = (addr << 8) + v;
  254:                         } else {             // data
  255:                                 buf[dcnt++] = (UB)v;
  256:                         }
  257:                 }
  258:                 if (dcnt > 0) {
  259:                         // if we have address specification, then the first address
  260:                         // to be used as the designated address after suitable adjustment.
  261:                         if (a_addr != 0) {
  262:                                 offset = a_addr - addr;
  263:                                 a_addr = 0;
  264:                         }
  265:                         addr += offset;
  266:                         if (addr < loaddr || addr - 1 > hiaddr - dcnt)
  267:                                         return E_RANGE;
  268:                         if (writeMem(addr, buf, dcnt, 1) != dcnt)
  269:                                         return E_MACV;
  270:                         if (addr < s_addr) s_addr = addr;
  271:                         if ((addr += dcnt) > e_addr) e_addr = addr;
  272:                 }
  273:                 if (rtype < 0) break; // end
  274:         }
  275:         return E_OK;
  276: }
  277: /*
  278:         loading processing
  279: */
  280: EXPORT  ER       doLoading(W proto, UW addr, UW *range)
  281: {
  282:         ER     er;
  283: 
  284:         e_addr = s_addr = addr;                // load address
  285: 
  286:         if (range) {   // range specification
  287:                 loaddr = range[0];    // address lower limit
  288:                 hiaddr = range[1];    // address upper limit
  289:                 offset = range[2];    // address offset
  290:         } else {
  291:                 loaddr = 0;           // address lower limit
  292:                 hiaddr = 0xFFFFFFFF;  // address upper limit
  293:                 offset = 0;           // address offset
  294:         }
  295: 
  296:         if (proto & P_XMODEM) {        // XMODEM
  297:                 readFn = (FUNCP)xmodemRead;
  298:                 blkptr = blkno = blksz = 0;
  299:         } else {               // no protocol
  300:                 readFn = (FUNCP)textRead;
  301:         }
  302: 
  303:         if (proto & P_SFORM) { // S format
  304:                 er = loadSform();
  305:                 if (er == E_END) er = E_LOAD;
  306:         } else {               // memory image
  307:                 er = loadImage();
  308:         }
  309: 
  310:         // read termination processing
  311:         if (proto & P_XMODEM) xmodemEnd(er);
  312: 
  313:         // wait until there is no more data
  314:         purgeInput();
  315: 
  316:         if (er == E_END) er = E_OK;
  317:         DSP_LF;
  318:         if (er == E_OK) {
  319:                 e_addr--;
  320:                 if (range) {
  321:                         range[0] = s_addr;   // load address
  322:                         range[1] = e_addr;
  323:                         s_addr -= offset;
  324:                         e_addr -= offset;
  325:                 }
  326:                 DSP_F5(S,"Loaded: ", 08X,s_addr, S," -> ", 08X,e_addr, CH,'\n');
  327:         }
  328:         return er;
  329: }