/* -------------------------------------------------------------------- hc11debug - Debugger for the Motorola 68HC11 Copyright (C) 2004-2020 Dominic Radermacher Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. -------------------------------------------------------------------- */ #include #include #include /* exit() */ #include /* strcmp() */ #include /* isdigit() */ #include /* read(), write(), sleep(), tcgetattr() */ #include /* tcgetattr() */ #include /* open() */ #include /* open() */ #include /* open() */ #include "hc11tools.h" #include "s19stuff.h" #include "serial.h" #include "talker.h" #include "tty.h" #include "ui.h" #define DEFAULT_SERDEV "/dev/ttyUSB0" /* -------------------------------------------------------------------- Function prototypes -------------------------------------------------------------------- */ int f_readline(FILE *f, char *buf, int size); void usage(char *progname); int is_chardev(char *file); int parse_args(int argc, char **argv); int load_talker(struct obj *bo); int parse_cmd(int fd, char *cmd); boolean any(char *str, char c); int arg_val(char *arg); /* -------------------------------------------------------------------- Global variables -------------------------------------------------------------------- */ char *device; /* device where the board is connected to */ boolean skipload, extmem; int is_chardev(char *file) { struct stat stbuf; if(stat(file, &stbuf) == -1) { return -1; } if((stbuf.st_mode & S_IFMT) != S_IFCHR) { return -1; } return 0; } int parse_args(int argc, char **argv) { int i; char *p; for(i=1; istart_addr=0xffff; bo->end_addr=0x0000; for(i=0; i<(int)sizeof(bo->code); bo->code[i++]=0); printf("Loading talker code...\n"); for(i=0; xx_talk[i] != 0; ) { for(k=i; xx_talk[k] != '\n'; k++); xx_talk[k++]=0; parse_s19_line(bo, &xx_talk[i]); i=k; } printf("Loading IRQ vectors...\n"); for(i=0; talk_irqvec[i] != 0; ) { for(k=i; talk_irqvec[k] != '\n'; k++); talk_irqvec[k++]=0; parse_s19_line(bo, &talk_irqvec[i]); i=k; } return 0; } void usage(char *progname) { printf("usage: %s [options] \n", progname); printf("\toptions:\n"); printf("\t-d \tserial device to use (default: %s)\n", DEFAULT_SERDEV); printf("\t--skipload\tskip bootload process (talker already running)\n"); printf("\t--extmem\tenable external bus\n"); exit(5); } /* * any --- does str contain c? */ boolean any(char *str, char c) { while(*str != 0) { if(*str++ == c) { return true; } } return false; } /* -------------------------------------------------------------------- evaluate the decimal value of the argument. input can be binary %01010011, hexadecimal $0f or decimal 45 values -------------------------------------------------------------------- */ int arg_val(char *arg) { int val=0; if(*arg == '%') { /* binary constant */ arg++; while(any("01", *arg) == true) { printf("%s -> %i\n", arg, val); val = (val * 2) + ((*arg++)-'0'); } } else if(*arg == '@') { /* octal constant */ arg++; while(any("01234567", *arg) == true) { val = (val * 8) + ((*arg++)-'0'); } } else if(*arg == '$') { /* hex constant */ arg++; while(any("0123456789abcdefABCDEF", *arg) == true) { if(*arg > '9') { val = (val * 16) + 10 + (tolower(*arg++)-'a'); } else { val = (val * 16) + ((*arg++)-'0'); } } } else if(any("0123456789", *arg) == true) { /* decimal constant */ while(*arg >= '0' && *arg <= '9') { val = (val * 10) + ((*arg++)-'0'); } } else { printf("error while parsing argument '%s'\n", arg); return 0; } return val; } int parse_cmd(int fd, char *cmd) { char *p; uint8_t buf[256]; int addr=0, len=0, val=0; struct obj code; struct mcu_regs myregs; if(strncmp(cmd, "md ", 3) == 0) { if((p=strchr(cmd+3, ' ')) != NULL) { /* we've got 2 args */ *p++=0; len=arg_val(p); if(len > 256) { printf("I would not do that if I where you (hint: md [len])\n"); return 0; } } else { len=16; } addr=arg_val(cmd+3); printf("memory dump from addr $%04x (len = %i)\n", addr, len); read_mcu_mem(fd, addr, buf, len); ui_show_mem(addr, buf, len); } else if(strncmp(cmd, "ms ", 3) == 0) { if((p=strchr(cmd+3, ' ')) != NULL) { *p++=0; val=arg_val(p); if(val > 255) { printf("value must be 0 .. 255\n"); return 0; } } else { printf("hint: ms \n"); return 0; } addr=arg_val(cmd+3); printf("setting value at addr $%04x to $%02x\n", addr, val); buf[0]=val; write_mcu_mem(fd, addr, buf, 1); } else if(strncmp(cmd, "go ", 3) == 0) { addr=arg_val(cmd+3); printf("Starting program at 0x%04x\n", addr); read_mcu_regs(fd, &myregs); myregs.pc=addr; write_mcu_regs(fd, &myregs); ui_show_mcu_regs(&myregs); } else if(strncmp(cmd, "load ", 5) == 0) { load_s19file(&code, cmd+5); /* load s19 source file */ addr=code.start_addr; len=code.end_addr - code.start_addr; if(len > 255) { printf("sorry, currently we can load a maximum of 256 bytes\n"); return -1; } printf("Writing %i byte starting from addr $%04x (this may take a while)\n", len, addr); write_mcu_mem(fd, addr, &code.code[addr], len); printf("Done\n"); } return 0; } int main(int argc, char **argv) { int fd, i, k; struct obj bootcode; struct mcu mymcu; struct mcu_regs myregs; char *cmd; uint8_t b; uint8_t buf[16]; if(argc < 2) { usage(argv[0]); } device=DEFAULT_SERDEV; skipload=false; extmem=false; /* we do not use external bus per default */ i=parse_args(argc, argv); if((fd=serial_open(device, B1200, CS8+CLOCAL)) < 0) { fprintf(stderr, "error: can not open '%s'\n", device); return 5; } if(skipload == false) { if(i < argc) { load_s19file(&bootcode, argv[i]); /* load s19 source file */ } else { load_talker(&bootcode); } if(bootcode.start_addr != 0) { fprintf(stderr, "error: program must start at address $0000\n"); return 1; } if(upload_firmware(fd, &bootcode) != 0) { return 5; /* makes no sense to continue then */ } sleep(1); } /* if(serial_setspeed(fd, B9600) != 0) { printf("failed to switch switching baudrate\n"); exit(5); } */ mymcu.devid=0; mymcu.maskid=0; /* try to detect mcu type */ read_mcu_mem(fd, 0x103c, buf, 1); /* either 0x0c or 0x0d seems bootstrap mode */ b=(buf[0]>>4); if((b & 4) == 4) { /* SMOD=1 - special mode */ if((b & 8) == 8) { read_mcu_mem(fd, 0xbfd4, buf, 2); mymcu.devid=(buf[0]<<8)+buf[1]; read_mcu_mem(fd, 0xbfd2, buf, 2); mymcu.maskid=(buf[0]<<8)+buf[1]; } if((b & 2) == 2) { printf("=> Special Test mode\n"); } else { // printf("=> Special Bootstrap mode\n"); if(extmem == true) { // printf("enabling external bus\n"); buf[0] |= 0x20; // write_mcu_mem(fd, 0x103c, buf, 1); } } } tcflush(fd, TCIOFLUSH); i=0; tty_init(); tty_setscrollregion(1, tty_height()-4); tty_gotoxy(1, 1); tty_cls(); while((k=tty_getkey()) != KEY_ESC) { ui_show_mcu_type(&mymcu); if(serial_rx_empty(fd) != 0) { /* when NOT empty */ read_byte(fd, &b); if(b == 0x4a) { /* SWI */ swi_handler(fd, &myregs); } else { printf("trap code %02x\n", b); } } if(k == 's') { /* 's' */ printf("Stopping MCU (setting to idle loop)\n"); read_mcu_regs(fd, &myregs); myregs.pc=0x000f; write_mcu_regs(fd, &myregs); ui_show_mcu_regs(&myregs); i=0; } else if(k == 'r') { /* r */ if(read_mcu_regs(fd, &myregs) == 0) { ui_show_mcu_regs(&myregs); } } else if(k == KEY_ENTER) { cmd=ui_enter_cmd(NULL); parse_cmd(fd, cmd); } else if(k == KEY_TIMEOUT) { if(read_mcu_regs(fd, &myregs) == 0) { ui_show_mcu_regs(&myregs); } } else { printf("keycode %04x counter %i\n", k, i); } i++; } tty_reset(); close(fd); return 0; }