/* * Morrow's S record down loader * Len Edmondson * May 1984 * * S record types */ #define until(a) while(!(a)) #define XON 17 #define XOFF 19 #define BUFSIZE 1024 #define START '0' #define SHIP2 '1' #define SHIP3 '2' #define TERM3 '8' #define TERM2 '9' #define YES 1 #define NO 0 #define IBUFSIZE 256 #define GBIADDR 0xff0010 struct gbi /* Godbout interfacer */ { char data, status, mode, command, xint, rint, rfu, select; }; char sum = 0; char db = NO; char ibuf [IBUFSIZE]; char buf [BUFSIZE]; char *ip, *op, *low = 0x400, *high; int icount = 0; long lineno = 0; struct gbi *gbi = GBIADDR; main (ac, av) char **av; { extern char *sbrk(); ip = op = (char *) ibuf; high = sbrk(0); if (ac != 1) db = YES; sstack (); logo (); sinit (); /* Hardward initialize */ for (;;) { readline (buf); stop (); process (buf); prs ("."); start (); } } /* * <1 byte data count> * <1 byte data count><2 byte address> * <1 byte data count><3 byte address> * <1 byte data count><3 byte address> * <1 byte data count><3 byte address> */ process (a) char *a; { static char *oldaddress; static char type, *olda, *address; static char namebuf [BUFSIZE]; static char obuf [114]; static long count, x; static (*f)(); sum = 0; olda = a; a++; /* skip S */ type = *a++; if (!index ("01289", type)) { complain ("Unknown S-record type\n"); } count = htoi (a); a += 2; if (count * 2 + 5 != strlen (olda)) { complain ("Byte data count error.\n"); } /* * address */ if (type == START) { x = (long) namebuf; } else { x = htoi (a); a += 2; x *= 256; x += htoi (a); a += 2; if (type == SHIP3 || type == TERM3) { x *= 256; x += htoi (a); a += 2; } } if (address && x != (long) address) { sprintf (obuf, "Address jump %lx - %lx\n", address, x); prs (obuf); } address = (char *) x; if (!db && low <= address && address < high) { prs("Address collision between the receiver and the received.\n"); sprintf (buf, "Address %lx\n", address); prs (buf); exit (); } /* * data */ switch (type) { case SHIP2: { count -= 3; break; } case SHIP3: { count -= 4; break; } case TERM2: case TERM3: { count = 0; break; } case START: { count--; break; } } while (count--) { if (db && type != START) { htoi (a); } else { *address++ = htoi (a); } a +=2; } /* * checksum */ htoi (a); a += 2; sum++; if (sum) { complain ("Checksum error.\n"); } if (*a != '\n') { complain ("Missing NEWLINE\n"); } switch (type) { case START: { prs (namebuf); prs ("\n"); break; } case TERM2: case TERM3: { prs ("\nSuccessful download\n"); prs ("Execution starts at "); prhex (address); prs ("\n"); if (!db) { f = address; (*f)(); } exit (); } } } complain (a) char *a; { prs (buf); sprintf (buf, "line %ld: %s\n", lineno, a); prs (buf); exit (); } readline (a) char *a; { static char c; for (;;) { c = sgetc () & 0177; /* get a char from hardware */ if (c == '\r') /* ignore return */ continue; *a++ = c; if (c == '\n') break; } *a = 0; lineno++; } /* * Godbout interfacer 4 I/O space address. * * From Interfacer 4 technical manual, page 33. */ #define BASE 16 #define DATA BASE #define STATUS (BASE + 1) #define MODE (BASE + 2) #define COMMAND (BASE + 3) #define SELECT (BASE + 7) /* * Port select numbers */ #define PORT0 7 #define PORT1 6 #define PORT2 5 /* * Bits. */ #define OUTREADY (1 << 0) #define INREADY (1 << 1) /* * Modes. */ #define REG1 0x6e #define REG2 0x7e /* 19200 baud */ #define REG3 0x27 /* * Read a character. * Select the port, wait til ready, then read a character. */ sgetc () { if (icount) { checkin (); return pop (); } gbi->select = PORT1; until(gbi->status & INREADY) ; return gbi->data; } /* * Send character a to port b of Interfacer 4. */ sputc (a, b) { gbi->select = b; until(gbi->status & OUTREADY) ; gbi->data = a; } #define CONSTANT 200 stop () { long i; sputc (XOFF, PORT1); /* * Collect characters while it coasts to a stop */ for (i = 0; i < CONSTANT; i++) checkin (); } /* * Check to see if there's a character waiting at GBI port 1. */ checkin () { gbi->select = PORT1; while (gbi->status & INREADY) push (gbi->data); } start () { sputc (XON, PORT1); } /* * Hardware initialization. */ sinit () { static char c; gbi->select = PORT1; gbi->mode = REG1; gbi->mode = REG2; gbi->command = REG3; start (); /* * eat leading garbage */ for (;;) { c = sgetc (); if (c == 'S') { push (c); break; } } } htoi (a) char *a; { char i; i = hval (*a++); i *= 16; i += hval (*a); sum += i; return 0377 & i; } hval (a) char a; { if (isdigit (a)) { a += (0 - '0'); } else if (isupper (a)) { a += (10 - 'A'); } else if (islower (a)) { a += (10 - 'a'); } return a; } isdigit (a) { return '0' <= a && a <= '9'; } isupper (a) { return 'A' <= a && a <= 'Z'; } islower (a) { return 'a' <= a && a <= 'z'; } logo () { prs ("Morrow's S record receiver\n"); prs ("Using Godbout Interfacer 4 second serial port for input.\n"); prs ("9600 baud.\n"); prs ("XON XOFF protocol.\n"); sprintf (buf, "This receiver occupies memory %lx through %lx.\n", low, high); prs (buf); } /* * put a character on the input buffer */ push (a) { *ip++ = a; if (ip == (char *) ibuf + IBUFSIZE) ip = (char *) ibuf; icount++; } pop () { static char c; icount--; c = *op++; if (op == (char *) ibuf + IBUFSIZE) op = (char *) ibuf; return c; } prs (a) char *a; { for (; *a; a++) { if (*a == '\n') putchar ('\r'); putchar (*a); } } putchar (a) char a; { sputc (a, PORT0); } prdec (a) long a; { static char b [16]; sprintf (b, "%ld", a); prs (b); } prhex (a) long a; { static char b [16]; sprintf (b, "%lx", a); prs (b); }