📄 bsoload.c
字号:
/************************************************************* * File: mon/bsoload.c * Purpose: file loader for bso's tools * Author: Phil Bunce (pjb@carmel.com) * Revision History: * 970303 Cleaned up unused globals and functions */#include <termio.h>#include <mon.h>#define NOPROTO#ifdef NOPROTO#define _(x) ()#else#define _(x) x#endif#define REC_END 2#define REC_DATA 3#define REC_ERROR 4typedef unsigned long ADDR;void dlink_init_admin _(( void ));static int dlink_getcp _(( int ));static int dlink_getc _(( int ));int getBinRecord _(( int, char *, ADDR *, int * ));/* static void dlink_terminate _(( int )); *//************************************************************** loader for BSO's binary download format*** pkt ::= <len><msg><chksum>* msg ::= <type><address><recordlength><databytes>* * Note that a pkt can contain part of a msg. ie. a msg can start* in one pkt and continue in the next.** type: bits 2:0 number of address bytes minus 1 !!* 4:3 compression type ( 0 = none )* 6:5 zeros* 7 set if termination record with initial pc** len: total unescaped bytes in <msg>** recordlength: length is <databytes>** checksum: a one byte ones complement sum of all unescaped record bytes,* except the record length and the checksum itself** Since the protocol is the start/stop protocol and the communication supports* a user interrupt character also when downloading these characters have to be * escaped when they appear in the data stream:** Esc ( 0x1b ) --> 0x1b 0x1c * Intr ( 0x03) --> 0x1b 0x1d* Crtl-S ( 0x13 ) --> 0x1b 0x1f* Crtl-Q ( 0x11 ) --> 0x1b 0x1e** Any byte in the download record may have to be escaped, even the one in* the record length or the checksum.**/enum e_status{ OK, ERROR};#define ESC_DLE 0x1c#define ESC_INTR 0x1d#define ESC_XON 0x1e#define ESC_XOFF 0x1f#define ASCII_DLE 0x1b#define ASCII_INTR 0x03#define ASCII_XON 0x11#define ASCII_XOFF 0x13#define ASCII_ACK 0x06#define ASCII_NAK 0x15#define MAX_SRECLEN 250 /* 255 when including 4 address bytes and 1 checksum byte */#define MAX_DATALEN (MAX_SRECLEN + 10)#define MAX_LINELEN (2 * MAX_DATALEN)static char recordLine [MAX_LINELEN];/* ========================================================================= * * Binary record support * * ========================================================================= */#define DLINK_BUFSIZE 255static char *dlink_buffer = recordLine; /* note its size and usage ! */static char *dlink_rp;static int dlink_bytes_left;static int dlink_sum;static int dlink_ack_yet; /* send ack before receiving next packet */static int lbfn = 0;static int bcnt = 0;static char lwbuf[256];static int dlink_stopped;extern Ulong nextaddr; static char *dlerrs[] = {0,"bad char","bad length","bad type", "bad chksum", "out of symbol space"};/************************************************************** do_lo(ac,av)*/do_lo(ac,av)int ac;char *av[];{struct termio tbuf;int i,fd,err,s,len;int errs[6];Ulong start_address;char ch;fd = STDIN;ioctl_xvwlo(fd);dlink_init_admin();printf("Downloading from tty0, ^C to abort\n");for (;;) { s = getBinRec(fd,recbuf,&nextaddr, &len); /* ** the last record in the download sequence ** contains the start address */ start_address = nextaddr; if (s == REC_DATA) memwrite(recbuf,len,0); if (s == REC_ERROR) { /* dlink_terminate( fd ); */ s = -3; } if (s < 0) { err++; errs[0-s]++; } else tot += len; if ( s == REC_END ) break; }if (err) { printf("\n%d errors\n",err); for (i=1;i<6;i++) if (errs[i]) printf(" %3d %s\n",errs[i],dlerrs[i]); }else printf("!540!pc=%08x\n", start_address ); writec(1,CNTRL('q'));dlink_stopped = 0;}/************************************************************** low_read( fd, n )*/low_read( fd, n )int fd,n;{ if ( n > 256 ) n = 256; if (dlink_stopped) writec( 1, CNTRL('q')); lbfn = read( fd, lwbuf, n ); writec( 1, CNTRL('s')); dlink_stopped = 1; bcnt = -1;} /************************************************************** static unsigned char*/static unsigned chario_getc( fd )int fd;{ char c; int n; scandevs(); if ( lbfn == 0 ) { /* ** now block until something is received */ if (dlink_stopped) writec( 1, CNTRL( 'q' ) ); while ( (n = read( fd, &c, 1 ) ) == 0 ) { scandevs(); } writec( 1, CNTRL( 's' ) ); dlink_stopped = 1; } else { lbfn--; bcnt++; c = lwbuf[bcnt]; } return c;}/************************************************************* * Function : sRecordAck * Arguments : OK: valid record; ERROR: invalid record * Returns : - * Globals : - * Modifies : - * Description : output ACK or NACK signal when configurated to do so */static void sRecordAck( fd, stat )int fd;int stat;{ if ( stat == OK ) { writec( 1, CNTRL( ASCII_ACK ) ); } else { writec( 1, CNTRL( ASCII_NAK ) ); }}/************************************************************* * Function : dlink_init_admin * Arguments : - * Returns : - * Globals : - * Modifies : - * Description : resets any dlink variables*/void dlink_init_admin( ){ dlink_ack_yet = 0; dlink_rp = dlink_buffer; dlink_bytes_left = 0; dlink_sum = 0;}/************************************************************* * Function : dlink_getcp * Arguments : - * Returns : character read * Globals : - * Modifies : - * Description : read one char from the datalink, after processing escaping * operates at lowest IO level */static int dlink_getcp( fd )int fd;{ int c; c = io_getc( fd ); if ( c == ASCII_DLE ) { switch ( c = io_getc( fd ) ) { case ESC_DLE: c = ASCII_DLE; break; case ESC_XOFF: c = ASCII_XOFF; break; case ESC_XON: c = ASCII_XON; break; case ESC_INTR: c = ASCII_INTR; /* * process interrupt c = comm_info.intr; */ break; } } return c;}/************************************************************* * Function : dlink_getc * Arguments : - * Returns : next character from buffered link * Globals : - * Modifies : - * Description : read a packet from the datalink stream if the current buffer * is empty, and return the next unprocessed char * Since retrying endlessly, no error status can be returned.*/static int dlink_getc( fd )int fd;{ unsigned char c; int i; char *cp;retry: if ( dlink_bytes_left ) { --dlink_bytes_left; c = *(unsigned char *)dlink_rp; ++dlink_rp; return c; } if ( dlink_ack_yet ) { /* need to send ACK for previously processed packet yet */ /* (delay the ACK to halt the sender while processing) */ sRecordAck( fd, OK ); dlink_ack_yet = 0; } do { /* read packet */ dlink_sum = 0; dlink_rp = dlink_buffer; dlink_bytes_left = dlink_getcp( fd ); /* length */ low_read( fd, dlink_bytes_left ); for ( cp = dlink_buffer, i = dlink_bytes_left; i; --i, ++cp ) { c = dlink_getcp( fd ); dlink_sum += c; *cp = c; } /* checksum */ dlink_sum += dlink_getcp( fd ); /* only NAK is send now, ACK on next packet or termination */ if ( (dlink_sum & 0xff) != 0xff ) { sRecordAck( fd, ERROR ); } } while ( (dlink_sum & 0xff) != 0xff ); /* till success or INTR */ dlink_ack_yet = 1; goto retry; /* use tail recursion -> for empty records */}#if 0 /* 970303 *//************************************************************** static void dlink_terminate( fd )*/static void dlink_terminate( fd )int fd;{ if ( dlink_ack_yet ) { /* need to send ACK for previously processed packet yet */ /* delay the ACK to halt the sender while processing */ sRecordAck( fd, OK ); dlink_ack_yet = 0; }}#endif/************************************************************* * Function : getBinRec * Arguments : buffer to place data, * ptr to address var, ptr to length * Returns : REC_END if termination record, REC_DATA if data, * REC_ERROR if an illegal record is received. * Globals : - * Modifies : - * Description : receive one binary data record, and return it and its length*/getBinRec( fd, dataBuffer, recordAddress, nrOfBytes ) int fd; char *dataBuffer; ADDR *recordAddress; int *nrOfBytes;{ ADDR addr; int rec_type; int nr; addr = 0L; /* * Typebyte: bit7 = terminating record with initial PC * bit6..5 = unused, zeros * bit4..3 = compress type * bit2..0 = address bytes */ rec_type = dlink_getc( fd ); if ( rec_type & 0x78 ) /* don't accept compressed data */ { return REC_ERROR; } /* read the address */ for ( nr = (rec_type & 0x07)+1; nr; --nr ) { addr = (addr << 8) | dlink_getc( fd ); } nr = dlink_getc( fd ); *nrOfBytes = nr; *recordAddress = addr; for ( ; nr; --nr ) { *dataBuffer++ = dlink_getc( fd ); tot++; } if ( rec_type & 0x80 ) /* ignore the data in a termination record */ { *nrOfBytes = 0; return REC_END; } return REC_DATA;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -