#include <stdlib.h>
#include <stdio.h>
-#include <getopt.h>
+#include <libgen.h>
#include <string.h>
#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 <device>] [-f <frequency>] firmware\n");
+ printf("usage: %s [-t] [-g] [-m <device>] [-f <frequency>] 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);
}
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) {
#include <poll.h>
#include <pthread.h>
#include "sim_avr.h"
+#include "sim_hex.h"
#include "avr_eeprom.h"
#define DBG(w)
} 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)
{
--- /dev/null
+/*
+ sim_hex.c
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#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;
+}
--- /dev/null
+/*
+ sim_hex.h
+
+ Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+
+ 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __SIM_HEX_H___
+#define __SIM_HEX_H___
+
+#include <stdint.h>
+
+// 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___ */