/* 6811 bootstrap monitor program */ /* IBM-PC Mix Power C version ** for Mini board by Fred Martin ** ** Macintosh version by Fred Martin ** ** from a program originally written by Henry Q. Minsky ** and subsequently modified by Randy Sargent */ /* #define MAC */ #define PC #define VERSION_HI 2 #define VERSION_LO 3 #define DATE "June 2, 1993" /* V1.0 February 10, 1992: first version V1.1 February 15, 1992: added "-delay" flag V1.2 February 28, 1992: deleted "-delay"; modified eeboot code to echo each character after eeprom burn V1.3 March 9, 1992: allowed Motorola S19 record to be named with ".hex" suffix in addition to ".s19" V1.4 March 25, 1992: added flags to allow downloading to a board with a normal serial line circuit V2.0 April 13, 1992: re-wrote bootstrap routine for "intelligent" eeprom burn added "-be" (bulk erase) flag to erase whole eeprom before download V2.0 Macintosh July 10, 1992: ported to Mac OS V2.1 July 24, 1992 added "-ram" flag for download to Forth board V2.2 July 24, 1992 converted DLM to Mon! V2.3 June 2, 1993 ported newest PC version back to Mac; added "analog" and "testmotors" routines; fixed help messages. */ /* Mini board has hardware echo of all characters; does not have additional 6811 firmware echo during bootstrap download mode. */ #include #include #include #ifdef MAC #include #include "serial_lib.h" #endif #ifdef PC #include #endif #ifdef PC int debug_serial= 0; int com_port= 0; /* PC: 0==COM1; 1==COM2 */ int bs_feedback= 0; /* if true, expect serial 6811 echo during bootstrap sequence */ int hardware_echo= 1; /* if true, expect serial hardware to echo characters during normal download */ int close_port= 0; /* if true, close serial port when exiting */ #endif #ifdef MAC extern int debug_serial; extern int com_port; extern int bs_feedback; extern int hardware_echo; extern int close_port; #endif int dl_to_ram= 0; /* if true, download to RAM not EEPROM */ char filename[128]; char filenamea[128]; char filenameb[128]; char bootstring[9][80]; /* prototypes */ void usage(); void usleep(long); void get_a_line(char *str); #ifdef MAC /* needs 'stricmp' routine */ int stricmp(char *s1, char *s2) { int i; for (i=0; s1[i] && s2[i]; i++) { if (((unsigned char)s1[i] | 0x20) > ((unsigned char)s2[i] | 0x20)) return 1; if (((unsigned char)s1[i] | 0x20) < ((unsigned char)s2[i] | 0x20)) return -1; } if (!(s1[i] | s2[i])) return 0; if (s1[i]) return 1; else return 0; } #endif void init_bootstring_ram(void) { strcpy(bootstring[0], "S12300008E00FF4FB710358625B7103CCE10001F2E80FC1D282086B0A72B860CA72D8D2B24"); strcpy(bootstring[1], "S123002020FC7F00DD2004860197DD8D5F167D00DD27048D102006183C8D5F183808180922"); strcpy(bootstring[2], "S123004026E939188FE700A600202D863E8D298D3B817327F6368D2C8F8D29188F32817280"); strcpy(bootstring[3], "S123006027E581702732815727BD815027B48142273F817727CD863F3CCE10001F2E80FC01"); strcpy(bootstring[4], "S1230080A72F38398D06368D031632393CCE10001F2E20FCA62F3839188FE10027A9A60074"); strcpy(bootstring[5], "S12300A043D7DE94DE270486168D1386028D0F2096188F378606CE103F9DBE860233B7102D"); strcpy(bootstring[6], "S12000C03BE7008A01B7103B8D0A7F103B3918CE6F9A200418CE0B29180926FC392D"); strcpy(bootstring[7], "S9030000FC"); /* strcpy(bootstring[8], "S9030000FC"); */ } void init_bootstring_eeprom(void) { strcpy(bootstring[0], "S12300008E00FF4FB71035CE10001F2E80FC1D282086B0A72B860CA72D8D2B20FC7F00E84F"); strcpy(bootstring[1], "S12300202004860197E88D5F167D00E827048D102006183C8D5F183808180926E939188F95"); strcpy(bootstring[2], "S1230040E700A600202D863E8D298D3B817327F6368D2C8F8D29188F32817227E58170274B"); strcpy(bootstring[3], "S123006032815727BD815027B48142273F817727CD863F3CCE10001F2E80FCA72F38398D51"); strcpy(bootstring[4], "S123008006368D031632393CCE10001F2E20FCA62F3839188FE10027A9A60043D7E994E9C8"); strcpy(bootstring[5], "S12300A0270486168D2386028D1F20968606B7103BB7103F8A01B7103B183C9DD918387F21"); strcpy(bootstring[6], "S12300C0103B188F8602CE103FB7103BE7008A01B7103B8D0A7F103B3918CE6F9A2004184A"); strcpy(bootstring[7], "S10B00E0CE0B29180926FC3996"); strcpy(bootstring[8], "S9030000FC"); } /***************************************************************/ /* The 6811 is in bootstrap mode, so send a 0xFF at 1200 baud. */ /* Then send 256 bytes of program. These will be loaded in */ /* starting at 0x00, and each byte will be echoed */ /***************************************************************/ /**************/ /* BREAKPOINT */ /**************/ #ifdef PC void breakpoint(void) { if (bioskey(1)) { /* not zero if key ready */ int key= bioskey(0) & 0xff; if (key == 27 || key == 3) exit(1); } } #endif #ifdef PC /*******************/ /* SERIAL ROUTINES */ /*******************/ #define BIOSCOM_INIT 0 #define BIOSCOM_WRITE 1 #define BIOSCOM_READ 2 #define BIOSCOM_STATUS 3 #define BAUD_1200 0x80 #define BAUD_9600 0xE0 #define EIGHT_BITS 0x03 #define DATA_READY 0x100 #define DATA_SET_READY 0x20 void serial_init_1200(void) { int status; status= bioscom(BIOSCOM_INIT, BAUD_1200 | EIGHT_BITS, com_port); if (debug_serial) printf("\tCOM%1d initialized; status= %#.4x\n", com_port+1, status); /* if (!(status & DATA_SET_READY)) { printf("Serial line not ready on COM%1d, exiting\n", com_port+1); exit(1); } */ } void serial_init_9600(void) { int status; status= bioscom(BIOSCOM_INIT, BAUD_9600 | EIGHT_BITS, com_port); if (debug_serial) printf("\tCOM%1d initialized; status= %#.4x\n", com_port+1, status); /* if (!(status & DATA_SET_READY)) { printf("Serial line not ready on COM%1d, exiting\n", com_port+1); exit(1); } */ } int serial_getchar(void) { int ret; while (1) { breakpoint(); if (bioscom(BIOSCOM_STATUS, 0, com_port) & DATA_READY) { /* data ready */ ret = bioscom(BIOSCOM_READ, 0, com_port); if (debug_serial) printf("read char >%04x< from serial\n", ret); return ret & 0xFF; } } } /* returns -1 if not ready */ int serial_getchar_nowait(void) { if (!(bioscom(BIOSCOM_STATUS, 0, com_port) & DATA_READY)) return -1; else return serial_getchar(); } void serial_putchar(int c) { if (debug_serial) printf("write char %02x to serial\n", c); bioscom(BIOSCOM_WRITE, (char)c, com_port); } void serial_putchar_getecho(int c) { int i; serial_putchar(c); if (hardware_echo) { if (debug_serial) printf("discarding echo "); if (c != (i= serial_getchar())) { /* hardware echoes the char */ printf("Serial line echo error (wanted %02x, got %02x)\n", c, i); exit(1); } } } /* reads chars until there are no more; returns value of last char read */ int serial_getlast_char(void) { int ch; int got_one= 0; if (debug_serial) printf(" Flushing to last char: "); try_again: while (bioscom(BIOSCOM_STATUS, 0, com_port) & DATA_READY) { ch= bioscom(BIOSCOM_READ, 0, com_port); if (debug_serial) printf("read >%04x< ", ch); got_one= 1; } breakpoint(); if (!got_one) goto try_again; if (debug_serial) printf("Returning >%02x<.\n", ch); return ch & 0xFF; } /* reads chars until there are no more */ void serial_flush(void) { if (debug_serial) printf(" Flushing serial port: "); while (bioscom(BIOSCOM_STATUS, 0, com_port) & DATA_READY) { int ch= bioscom(BIOSCOM_READ, 0, com_port); if (debug_serial) printf(" >%04x< ", ch); } if (debug_serial) printf("Done.\n"); } #endif /* send 's' until get prompt, 1 if successful, 0 if not */ int synch_with_board(void) { int j; serial_putchar('s'); serial_putchar('s'); serial_putchar('s'); serial_putchar('s'); serial_putchar('s'); printf("Synchronizing with board..."); for (j=0; j<20; j++) { int ch, lch; /* get characters until the last one; return the last valid char */ while (1) { /* usleep(55000L); */ lch= serial_getchar_nowait(); if (lch == -1) break; ch = lch; } if (ch == '>') { serial_flush(); break; } serial_putchar('s'); printf("."); fflush(stdout); usleep(55000L); } if (j == 20) { printf("failed.\n"); return 0; } else { printf("OK\n"); return 1; } } #ifdef MAC #define USLEEP_CLOCK CLOCKS_PER_SEC #endif #ifdef PC #define USLEEP_CLOCK CLK_TCK #endif void usleep(long usec) { clock_t finish; finish= clock() + (usec * (long)USLEEP_CLOCK) / 1000000L; while (clock() < finish); } /*****************/ /* HEX FUNCTIONS */ /*****************/ int hex_to_int(char ch) { if ('0' <= ch && ch <= '9') return ch - '0'; if ('a' <= ch && ch <= 'f') return ch - 'a' + 10; if ('A' <= ch && ch <= 'F') return ch - 'A' + 10; printf("Illegal hex digit >%c<\n", ch); return 0; } int decode_hex(char *str, int index) { int hi,lo; char chi,clo; chi = str[index]; clo = str[index+1]; hi = hex_to_int(chi); lo = hex_to_int(clo); return (hi*16)+lo; } void parsearg(int argc, char *argv[]) { int i= 1; if (argc == 0) usage(); while (i < argc) { if (!stricmp(argv[i], "-debug")) { debug_serial= 1; printf("Turning serial debugging on\n"); i++; continue; } if (!stricmp(argv[i], "-port")) { char *port= argv[i+1]; #ifdef PC if (!stricmp(port, "com1")) { printf("Using COM1\n"); com_port= 0; } else if (!stricmp(port, "com2")) { printf("Using COM2\n"); com_port= 1; } #endif #ifdef MAC if (!stricmp(port, "modem")) { printf("Using modem port\n"); com_port= 0; } else if (!stricmp(port, "printer")) { printf("Using printer port\n"); com_port= 1; } #endif else { printf("Unsupported com port `%s'\n\n", port); usage(); } i+=2; continue; } if (!stricmp(argv[i], "-mb")) { bs_feedback= 0; hardware_echo= 1; printf("Turning bootstrap feedback off, hardware echo on\n"); i++; continue; } if (!stricmp(argv[i], "-ram")) { dl_to_ram= 1; printf("Enabling external RAM\n"); i++; continue; } if (!stricmp(argv[i], "-noram")) { dl_to_ram= 0; printf("Disabling external RAM\n"); i++; continue; } if (!stricmp(argv[i], "-close")) { close_port= 1; printf("Will close serial port on exit\n"); i++; continue; } if (!stricmp(argv[i], "-ns")) { bs_feedback= 1; hardware_echo= 0; printf("Turning bootstrap feedback on, hardware echo off\n"); i++; continue; } #ifdef MAC if (!stricmp(argv[i], "-die")) { serial_cleanup(); exit(0); } #endif if (!stricmp(argv[i], "-help") || !stricmp(argv[i], "-h") || !stricmp(argv[i], "?") || !stricmp(argv[i], "-?")) { usage(); } i++; } } void usage(void) { #ifdef PC printf("usage: MON [-port COM1|COM2] [-mb] [-ns]\n"); #endif #ifdef MAC printf("usage: MON [-port modem|printer] [-mb] [-ns]\n"); #endif printf(" [-close] [-debug] [-help]\n\n"); #ifdef PC printf("\t-port COM1 or -port COM2 use specified serial port\n"); printf("\t (defaults to COM%1d)\n\n", com_port+1); #endif #ifdef MAC printf("\t-port modem use specified serial port\n"); printf("\t-port printer \n\n"); #endif printf("\t-mb assume Mini Board serial connection\n"); printf("\t (hardware echo of transmitted characters,\n"); printf("\t except during bootstrap; defaults %s)\n\n", ((bs_feedback==0)&&(hardware_echo==1)) ? "on" : "off"); printf("\t-ns assume normal serial connection\n"); printf("\t (defaults %s)\n\n", ((bs_feedback==1)&&(hardware_echo==0)) ? "on" : "off"); #ifdef MAC printf("\t-close close serial driver on exit (defaults %s)\n\n", close_port ? "on" : "off"); #endif printf("\t-ram,-noram enable external memory of 6811\n"); printf("\t (defaults %s)\n\n", dl_to_ram ? "on" : "off"); printf("\t-help prints this information\n\n"); exit(-1); } void main(int argc, char *argv[]) { char line_in[256]; int byte_count, data_byte, return_byte, i, j; int total_bytes, startaddh, startaddl; int bs_ix=0; #ifdef MAC OSErr err; #endif #ifdef PC int err; #endif FILE *userstream; #ifdef MAC /* console_options.txSize= 10; console_options.left= 0; */ #endif printf("MON: 6811 Bootstrap Monitor by Fred Martin\n"); #ifdef PC printf("PC Version %d.%d %s %s\n\n", VERSION_HI, VERSION_LO, __DATE__, __TIME__); #endif #ifdef MAC printf("Macintosh Version %d.%d %s\n\n", VERSION_HI, VERSION_LO, DATE); #endif #ifdef MAC argc= ccommand(&argv); csetmode(C_RAW, stdin); #endif parsearg(argc, argv); if (dl_to_ram == 0) init_bootstring_eeprom(); else init_bootstring_ram(); total_bytes=0; /* initialize 1200 baud port 8 bits no parity */ if (err= serial_init_1200()) { fprintf(stderr, "Unable to initialize serial port for 1200 baud.\n"); #ifdef MAC fprintf(stderr, "Please check that Appletalk is disabled for the port you would like to use.\n"); #endif exit(err); } printf("Downloading eeprom loader to RAM at 1200 baud..."); /* send initial 0xff */ serial_putchar(0xff); while (1) { strcpy(line_in, bootstring[bs_ix++]); if ((line_in[0] == 'S') && (line_in[1] == '9')) break; byte_count = (decode_hex(line_in,2) - 3); /* loop sending data bytes from the s-record */ for (i = 0; i < byte_count; i++) { breakpoint(); data_byte = decode_hex(line_in,(2*i)+8); serial_putchar(data_byte); if (bs_feedback) serial_getchar(); getanother: if (serial_getchar_nowait() != -1) { if (debug_serial) fprintf(stderr, "Extra char on serial input\n"); goto getanother; } if (!(total_bytes % 32)) printf("\n"); printf("."); fflush(stdout); total_bytes++; } } /* now send 256-byte_count 0's to fill the rest of ram */ while (total_bytes < 256) { breakpoint(); serial_putchar(0); if (bs_feedback) serial_getchar(); getanother2: if (serial_getchar_nowait() != -1) { if (debug_serial) fprintf(stderr, "Extra char on serial input\n"); goto getanother2; } if (!(total_bytes % 32)) printf("\n"); printf("_"); fflush(stdout); total_bytes++; } printf("\n%d total bytes (boot loader done)\n\n", total_bytes); /* now download the user prog */ /* initialize 9600 baud port 8 bits no parity */ usleep(110000L); /* wait for last char to transmit */ #ifdef MAC serial_cleanup(); #endif if (err= serial_init_9600()) { fprintf(stderr, "Unable to initialize serial port for 9600 baud\n"); exit(err); } /* synchronize */ if (!synch_with_board()) { usage(); #ifdef MAC serial_cleanup(); #endif exit(0); } mon_help(); interaction_loop(); #ifdef MAC serial_cleanup(); #endif exit(0); } interaction_loop() { char buffer[80]; char cmd[20]; int addr, data; int val; while (1) { printf("MON> "); fflush(stdout); get_a_line((char *)&buffer); if (buffer[0] == 0) continue; if (buffer[0] == 'q') { printf("Bye!\n"); break; } sscanf(buffer, "%s %x %x", cmd, &addr, &data); if ((!stricmp(cmd, "help")) || (!stricmp(cmd, "h")) || (cmd[0] == '?')) { mon_help(); } else if ((!stricmp(cmd, "read")) || (!stricmp(cmd, "r"))) { val= board_read(addr); printf("Value at address %04X is %02X (%d decimal)\n", addr, val, val); } else if ((!stricmp(cmd, "write")) || (!stricmp(cmd, "w"))) { val= board_write(addr, data); printf("Wrote %02X to address %04X (returned %02X)\n", data & 0xFF, addr, val); } else if ((!stricmp(cmd, "eeprom")) || (!stricmp(cmd, "e"))) { val= board_eeprom_write(addr, data); printf("Wrote %02X to eeprom address %04X (returned %02X)\n", data & 0xFF, addr, val); if (addr == 0x103F) printf("Programmed CONFIG register; restart MON and board to observe changes.\n"); } else if ((!stricmp(cmd, "bulk")) || (!stricmp(cmd, "b"))) { val= board_bulk_erase(addr); printf("Bulk erased EEPROM. Restart board to read CONFIG register ($103F).\n"); } else if ((!stricmp(cmd, "analog"))) { val= board_get_analog(addr); printf("Value of port %d is %02X (%d decimal)\n", addr, val, val); } else if ((!stricmp(cmd, "testmotors"))) { board_test_motors(); } else if ((!stricmp(cmd, "digitals"))) { val= board_read(0x1003); printf("Digital port returns %02X (%d decimal)\n", val, val); } } } mon_help() { printf("MON responds to the following commands:\n\n"); printf("read read byte located at \n"); printf("write write byte to \n"); printf("eeprom write to eeprom \n"); printf("bulk bulk erase eeprom, program CONFIG reg with \n"); printf("analog read data from analog input 0 to 7\n"); printf("digitals read address $1003 (Mini Board digital inputs)\n"); printf("testmotors individually light each motor LED\n"); printf("quit leave MON\n"); printf("help print these instructions\n\n"); } board_read(int addr) { int val; serial_putchar_getecho('r'); serial_putchar_getecho((addr >> 8) & 0xFF); serial_putchar_getecho(addr & 0xFF); serial_putchar_getecho(0); serial_putchar_getecho(0); val= serial_getchar(); if (serial_getchar() != '>') { printf("Board prompt missing, exiting.\n"); exit(1); } return val; } board_write(int addr, int data) { int val; serial_putchar_getecho('w'); serial_putchar_getecho((addr >> 8) & 0xFF); serial_putchar_getecho(addr & 0xFF); serial_putchar_getecho(0); serial_putchar_getecho(data & 0xFF); val= serial_getchar(); if (serial_getchar() != '>') { printf("Board prompt missing, exiting.\n"); exit(1); } return val; } board_eeprom_write(int addr, int data) { int val; serial_putchar_getecho('p'); serial_putchar_getecho((addr >> 8) & 0xFF); serial_putchar_getecho(addr & 0xFF); serial_putchar_getecho(0); serial_putchar_getecho(data & 0xFF); val= serial_getchar(); if (serial_getchar() != '>') { printf("Board prompt missing, exiting.\n"); exit(1); } return val; } board_bulk_erase(int config) { int val; serial_putchar_getecho('p'); serial_putchar_getecho(0); serial_putchar_getecho(0); serial_putchar_getecho(0); serial_putchar_getecho(config & 0xFF); val= serial_getchar(); if (serial_getchar() != '>') { printf("Board prompt missing, exiting.\n"); exit(1); } return val; } /* ** ** board_get_analog: ** ** program analog system to retrieve input value ** ** ports numbered 0 to 7 ** */ #define ADR1 0x1031 /* A/D Result Register 1 */ #define ADCTL 0x1030 /* A/D Control/Status Register */ #define OPTION 0x1039 /* System Configuration Options */ #define ENABLE_ANALOG 0x80 /* bit mask to turn on analogs */ board_get_analog(int port) { int option; /* turn on analog subsystem */ option= board_read(OPTION); if (!(option & ENABLE_ANALOG)) { board_write(OPTION, option | ENABLE_ANALOG); } /* set analog to scan desired port */ board_write(ADCTL, port); /* get result */ return board_read(ADR1); } /* ** ** board_test_motors ** ** writes sequence of bits to test each motor on Mini Board 1.5 or 2.0 ** */ #define MOTOR_PORT 0x1004 board_test_motors() { if (dl_to_ram) { printf("Motor test must be run with external RAM disabled.\n"); printf("Restart MON with command-line flag \"-noram\" to enable this function.\n"); } else { printf("Testing..."); fflush(stdout); board_write(MOTOR_PORT, 0x10); usleep(500000L); board_write(MOTOR_PORT, 0x11); usleep(500000L); board_write(MOTOR_PORT, 0x20); usleep(500000L); board_write(MOTOR_PORT, 0x22); usleep(500000L); board_write(MOTOR_PORT, 0x40); usleep(500000L); board_write(MOTOR_PORT, 0x44); usleep(500000L); board_write(MOTOR_PORT, 0x80); usleep(500000L); board_write(MOTOR_PORT, 0x88); usleep(500000L); board_write(MOTOR_PORT, 0); printf("done.\n"); } } char getkey(); void get_a_line(char *buf) { char ch; int count= 0; while (1) { putchar('_'); putchar(8); ch= getkey(); if (ch == 8) { if (count != 0) { count--; buf--; putchar(' '); putchar(8); putchar(8); } else { putchar(7); /* beep */ } } else if ((ch == 13) || (ch == 3) || (ch == 10)) { putchar(' '); putchar('\n'); *buf= 0; return; } else if (ch < 32) { putchar(7); } else { putchar(ch); *(buf++)= ch; count++; } } } char getkey() { char ch; while ((ch = getchar()) == EOF); return ch; }