From: Michel Pollet Date: Wed, 23 Dec 2009 22:22:23 +0000 (+0000) Subject: run_avr et al. New HEX format loader X-Git-Url: http://git.rot13.org/?a=commitdiff_plain;h=a2c20ba4beff2186de521d35f137a0e2fef47779;p=simavr run_avr et al. New HEX format loader simavr can now load .hex files directly, It is obviously a lot more primitive than the ELF loader, but it works. You have to specify the MCU and the AVR frequency on the command line to run a .hex, otherwise simavr has no clue what it's suposed to do. Also reworked run_avr to get rid of getopt, moved the read_hex_string function into the new sim_hex.[ch], and now understand that the base addresd of code is not always zero. This allows loading of a bootloader (tada!) Signed-off-by: Michel Pollet --- diff --git a/simavr/sim/run_avr.c b/simavr/sim/run_avr.c index f39fb3b..aa202f3 100644 --- a/simavr/sim/run_avr.c +++ b/simavr/sim/run_avr.c @@ -21,86 +21,74 @@ #include #include -#include +#include #include #include "sim_avr.h" #include "sim_elf.h" #include "sim_core.h" #include "sim_gdb.h" -#include "avr_uart.h" +#include "sim_hex.h" -void hdump(const char *w, uint8_t *b, size_t l) -{ - uint32_t i; - if (l < 16) { - printf("%s: ",w); - for (i = 0; i < l; i++) printf("%02x",b[i]); - } else { - printf("%s:\n",w); - for (i = 0; i < l; i++) { - if (!(i & 0x1f)) printf(" "); - printf("%02x",b[i]); - if ((i & 0x1f) == 0x1f) { - printf(" "); - printf("\n"); - } - } - } - printf("\n"); -} +extern avr_kind_t * avr_kind[]; - -void display_usage() +void display_usage(char * app) { - printf("usage: simavr [-t] [-g] [-m ] [-f ] firmware\n"); + printf("usage: %s [-t] [-g] [-m ] [-f ] firmware\n", app); printf(" -t: run full scale decoder trace\n"); printf(" -g: listen for gdb connection on port 1234\n"); + printf(" Supported AVR cores:\n"); + for (int i = 0; avr_kind[i]; i++) { + printf(" "); + for (int ti = 0; ti < 4 && avr_kind[i]->names[ti]; ti++) + printf("%s ", avr_kind[i]->names[ti]); + printf("\n"); + } exit(1); } int main(int argc, char *argv[]) { - elf_firmware_t f; + elf_firmware_t f = {0}; long f_cpu = 0; int trace = 0; int gdb = 0; char name[16] = ""; - int option_count; - int option_index = 0; - - struct option long_options[] = { - {"help", no_argument, 0, 'h'}, - {"mcu", required_argument, 0, 'm'}, - {"freq", required_argument, 0, 'f'}, - {"trace", no_argument, 0, 't'}, - {"gdb", no_argument, 0, 'g'}, - {0, 0, 0, 0} - }; if (argc == 1) - display_usage(); - - while ((option_count = getopt_long(argc, argv, "tghm:f:", long_options, &option_index)) != -1) { - switch (option_count) { - case 'h': - display_usage(); - break; - case 'm': - strcpy(name, optarg); + display_usage(basename(argv[0])); + + for (int pi = 1; pi < argc; pi++) { + if (!strcmp(argv[pi], "-h") || !strcmp(argv[pi], "-help")) { + display_usage(basename(argv[0])); + } else if (!strcmp(argv[pi], "-m") || !strcmp(argv[pi], "-mcu")) { + if (pi < argc-1) + strcpy(name, argv[++pi]); + else + display_usage(basename(argv[0])); + } else if (!strcmp(argv[pi], "-f") || !strcmp(argv[pi], "-freq")) { + if (pi < argc-1) + f_cpu = atoi(argv[++pi]); + else + display_usage(basename(argv[0])); break; - case 'f': - f_cpu = atoi(optarg); - break; - case 't': + } else if (!strcmp(argv[pi], "-t") || !strcmp(argv[pi], "-trace")) { trace++; - break; - case 'g': - gdb++; - break; + } else if (!strcmp(argv[pi], "-g") || !strcmp(argv[pi], "-gdb")) { + gdb++; } } - elf_read_firmware(argv[argc-1], &f); + char * filename = argv[argc-1]; + char * suffix = strrchr(filename, '.'); + if (suffix && !strcasecmp(suffix, ".hex")) { + if (!name[0] || !f_cpu) { + fprintf(stderr, "%s: -mcu and -freq are mandatory to load .hex files\n", argv[0]); + exit(1); + } + f.flash = read_ihex_file(filename, &f.flashsize, &f.flashbase); + } else { + elf_read_firmware(filename, &f); + } if (strlen(name)) strcpy(f.mmcu, name); @@ -116,17 +104,12 @@ int main(int argc, char *argv[]) } avr_init(avr); avr_load_firmware(avr, &f); + if (f.flashbase) { + printf("Attempted to load a booloader at %04x\n", f.flashbase); + avr->pc = f.flashbase; + } avr->trace = trace; - // try to enable "local echo" on the first uart, for testing purposes - { - avr_irq_t * src = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_OUTPUT); - avr_irq_t * dst = avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ('0'), UART_IRQ_INPUT); - if (src && dst) { - printf("%s:%s activating uart local echo IRQ src %p dst %p\n", __FILE__, __FUNCTION__, src, dst); - avr_connect_irq(src, dst); - } - } // even if not setup at startup, activate gdb if crashing avr->gdb_port = 1234; if (gdb) { diff --git a/simavr/sim/sim_gdb.c b/simavr/sim/sim_gdb.c index 43225c8..a90bb69 100644 --- a/simavr/sim/sim_gdb.c +++ b/simavr/sim/sim_gdb.c @@ -32,6 +32,7 @@ #include #include #include "sim_avr.h" +#include "sim_hex.h" #include "avr_eeprom.h" #define DBG(w) @@ -49,33 +50,6 @@ typedef struct avr_gdb_t { } watch[32]; } avr_gdb_t; - // decode line text hex to binary -int read_hex_string(const char * src, uint8_t * buffer, int maxlen) -{ - uint8_t * dst = buffer; - int ls = 0; - uint8_t b = 0; - while (*src && maxlen--) { - char c = *src++; - switch (c) { - case 'a' ... 'f': b = (b << 4) | (c - 'a' + 0xa); break; - case 'A' ... 'F': b = (b << 4) | (c - 'A' + 0xa); break; - case '0' ... '9': b = (b << 4) | (c - '0'); break; - default: - if (c > ' ') { - fprintf(stderr, "%s: huh '%c' (%s)\n", __FUNCTION__, c, src); - return -1; - } - continue; - } - if (ls & 1) { - *dst++ = b; b = 0; - } - ls++; - } - - return dst - buffer; -} static void gdb_send_reply(avr_gdb_t * g, char * cmd) { diff --git a/simavr/sim/sim_hex.c b/simavr/sim/sim_hex.c new file mode 100644 index 0000000..6280320 --- /dev/null +++ b/simavr/sim/sim_hex.c @@ -0,0 +1,139 @@ +/* + sim_hex.c + + Copyright 2008, 2009 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + +#include +#include +#include +#include "sim_hex.h" + +// friendly hex dump +void hdump(const char *w, uint8_t *b, size_t l) +{ + uint32_t i; + if (l < 16) { + printf("%s: ",w); + for (i = 0; i < l; i++) printf("%02x",b[i]); + } else { + printf("%s:\n",w); + for (i = 0; i < l; i++) { + if (!(i & 0x1f)) printf(" "); + printf("%02x",b[i]); + if ((i & 0x1f) == 0x1f) { + printf(" "); + printf("\n"); + } + } + } + printf("\n"); +} + + // decode line text hex to binary +int read_hex_string(const char * src, uint8_t * buffer, int maxlen) +{ + uint8_t * dst = buffer; + int ls = 0; + uint8_t b = 0; + while (*src && maxlen--) { + char c = *src++; + switch (c) { + case 'a' ... 'f': b = (b << 4) | (c - 'a' + 0xa); break; + case 'A' ... 'F': b = (b << 4) | (c - 'A' + 0xa); break; + case '0' ... '9': b = (b << 4) | (c - '0'); break; + default: + if (c > ' ') { + fprintf(stderr, "%s: huh '%c' (%s)\n", __FUNCTION__, c, src); + return -1; + } + continue; + } + if (ls & 1) { + *dst++ = b; b = 0; + } + ls++; + } + + return dst - buffer; +} + +uint8_t * read_ihex_file(const char * fname, uint32_t * dsize, uint32_t * start) +{ + if (!fname || !dsize) + return NULL; + FILE * f = fopen(fname, "r"); + if (!f) { + perror(fname); + return NULL; + } + uint8_t * res = NULL; + uint32_t size = 0; + uint32_t base = ~0; + + while (!feof(f)) { + char line[128]; + if (!fgets(line, sizeof(line)-1, f)) + continue; + if (line[0] != ':') { + fprintf(stderr, "AVR: '%s' invalid ihex format (%.4s)\n", fname, line); + break; + } + uint8_t bline[64]; + + int len = read_hex_string(line + 1, bline, sizeof(bline)); + if (len <= 0) + continue; + + uint8_t chk = 0; + { // calculate checksum + uint8_t * src = bline; + int tlen = len-1; + while (tlen--) + chk += *src++; + chk = 0x100 - chk; + } + if (chk != bline[len-1]) { + fprintf(stderr, "%s: %s, invalid checksum %02x/%02x\n", __FUNCTION__, fname, chk, bline[len-1]); + break; + } + if (bline[3] != 0) { + if (bline[3] != 1) { + fprintf(stderr, "%s: %s, unsupported check type %02x\n", __FUNCTION__, fname, bline[3]); + break; + } + continue; + } + uint16_t addr = (bline[1] << 8) | bline[2]; + if (base == ~0) { + base = addr; // stadt address + } + if (addr != base + size) { + fprintf(stderr, "%s: %s, offset out of bounds %04x expected %04x\n", __FUNCTION__, fname, addr, base+size); + break; + } + res = realloc(res, size + bline[0]); + memcpy(res + size, bline + 4, bline[0]); + size += bline[0]; + } + *dsize = size; + if (start) + *start = base; + fclose(f); + return res; +} diff --git a/simavr/sim/sim_hex.h b/simavr/sim/sim_hex.h new file mode 100644 index 0000000..caf0afc --- /dev/null +++ b/simavr/sim/sim_hex.h @@ -0,0 +1,38 @@ +/* + sim_hex.h + + Copyright 2008, 2009 Michel Pollet + + This file is part of simavr. + + simavr is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + simavr is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with simavr. If not, see . + */ + + +#ifndef __SIM_HEX_H___ +#define __SIM_HEX_H___ + +#include + +// parses a hex text string 'src' of at max 'maxlen' characters, decodes it into 'buffer' +int read_hex_string(const char * src, uint8_t * buffer, int maxlen); + +// reads IHEX file 'fname', puts it's decoded size in *'dsize' and returns +// a newly allocated buffer with the binary data (or NULL, if error) +uint8_t * read_ihex_file(const char * fname, uint32_t * dsize, uint32_t * start); + +// hex dump from pointer 'b' for 'l' bytes with string prefix 'w' +void hdump(const char *w, uint8_t *b, size_t l); + +#endif /* __SIM_HEX_H___ */