a function, sim_setup_firmware(), that also handles ELF firmware.
Add a test, test_atmega88_hex.c, and use the new function in other tests.
} else 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)
+ if (pi < argc-1) {
snprintf(name, sizeof(name), "%s", argv[++pi]);
- else
+ strcpy(f.mmcu, name);
+ } else {
display_usage(basename(argv[0]));
+ }
} else if (!strcmp(argv[pi], "-f") || !strcmp(argv[pi], "--freq")) {
- if (pi < argc-1)
+ if (pi < argc-1) {
f_cpu = atoi(argv[++pi]);
- else
+ f.frequency = f_cpu;
+ } else {
display_usage(basename(argv[0]));
+ }
} else if (!strcmp(argv[pi], "-i") || !strcmp(argv[pi], "--input")) {
if (pi < argc-1)
vcd_input = argv[++pi];
} else if (!strcmp(argv[pi], "-ff")) {
loadBase = AVR_SEGMENT_OFFSET_FLASH;
} else if (argv[pi][0] != '-') {
- char * filename = argv[pi];
- 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);
- }
- ihex_chunk_p chunk = NULL;
- int cnt = read_ihex_chunks(filename, &chunk);
- if (cnt <= 0) {
- fprintf(stderr, "%s: Unable to load IHEX file %s\n",
- argv[0], argv[pi]);
- exit(1);
- }
- printf("Loaded %d section of ihex\n", cnt);
- for (int ci = 0; ci < cnt; ci++) {
- if (chunk[ci].baseaddr < (1*1024*1024)) {
- f.flash = chunk[ci].data;
- f.flashsize = chunk[ci].size;
- f.flashbase = chunk[ci].baseaddr;
- printf("Load HEX flash %08x, %d\n", f.flashbase, f.flashsize);
- } else if (chunk[ci].baseaddr >= AVR_SEGMENT_OFFSET_EEPROM ||
- chunk[ci].baseaddr + loadBase >= AVR_SEGMENT_OFFSET_EEPROM) {
- // eeprom!
- f.eeprom = chunk[ci].data;
- f.eesize = chunk[ci].size;
- printf("Load HEX eeprom %08x, %d\n", chunk[ci].baseaddr, f.eesize);
- }
- }
- } else {
- if (elf_read_firmware(filename, &f) == -1) {
- fprintf(stderr, "%s: Unable to load firmware from file %s\n",
- argv[0], filename);
- exit(1);
- }
- }
+ sim_setup_firmware(argv[pi], loadBase, &f, argv[0]);
}
}
+ // Frequency and MCU type were set early so they can be checked when
+ // loading a hex file. Set them again because they can also be set
+ // in an ELF firmware file.
+
if (strlen(name))
strcpy(f.mmcu, name);
if (f_cpu)
#include <stdlib.h>
#include <string.h>
#include "sim_hex.h"
+#include "sim_elf.h"
// friendly hex dump
void hdump(const char *w, uint8_t *b, size_t l)
return res;
}
+/* Load a firmware file, ELF or HEX format, from filename, based at
+ * loadBase, returning the data in *fp ready for loading into
+ * the simulated MCU. Progname is the current program name for error messages.
+ *
+ * Included here as it mostly specific to HEX files.
+ */
+
+void
+sim_setup_firmware(const char * filename, uint32_t loadBase,
+ elf_firmware_t * fp, const char * progname)
+{
+ char * suffix = strrchr(filename, '.');
+
+ if (suffix && !strcasecmp(suffix, ".hex")) {
+ if (!(fp->mmcu[0] && fp->frequency > 0)) {
+ printf("MCU type and frequency are not set "
+ "when loading .hex file\n");
+ }
+ ihex_chunk_p chunk = NULL;
+ int cnt = read_ihex_chunks(filename, &chunk);
+ if (cnt <= 0) {
+ fprintf(stderr,
+ "%s: Unable to load IHEX file %s\n", progname, filename);
+ exit(1);
+ }
+ printf("Loaded %d section(s) of ihex\n", cnt);
+
+ for (int ci = 0; ci < cnt; ci++) {
+ if (chunk[ci].baseaddr < (1*1024*1024)) {
+ if (fp->flash) {
+ printf("Ignoring chunk %d, "
+ "possible flash redefinition %08x, %d\n",
+ ci, chunk[ci].baseaddr, chunk[ci].size);
+ free(chunk[ci].data);
+ chunk[ci].data = NULL;
+ continue;
+ }
+ fp->flash = chunk[ci].data;
+ fp->flashsize = chunk[ci].size;
+ fp->flashbase = chunk[ci].baseaddr;
+ printf("Load HEX flash %08x, %d at %08x\n",
+ fp->flashbase, fp->flashsize, fp->flashbase);
+ } else if (chunk[ci].baseaddr >= AVR_SEGMENT_OFFSET_EEPROM ||
+ (chunk[ci].baseaddr + loadBase) >=
+ AVR_SEGMENT_OFFSET_EEPROM) {
+ // eeprom!
+ if (fp->eeprom) {
+
+ // Converting ELF with .mmcu section will do this.
+
+ printf("Ignoring chunk %d, "
+ "possible eeprom redefinition %08x, %d\n",
+ ci, chunk[ci].baseaddr, chunk[ci].size);
+ free(chunk[ci].data);
+ chunk[ci].data = NULL;
+ continue;
+ }
+ fp->eeprom = chunk[ci].data;
+ fp->eesize = chunk[ci].size;
+ printf("Load HEX eeprom %08x, %d\n",
+ chunk[ci].baseaddr, fp->eesize);
+ }
+ }
+ free(chunk);
+ } else {
+ if (elf_read_firmware(filename, fp) == -1) {
+ fprintf(stderr, "%s: Unable to load firmware from file %s\n",
+ progname, filename);
+ exit(1);
+ }
+ }
+}
#ifdef IHEX_TEST
// gcc -std=gnu99 -Isimavr/sim simavr/sim/sim_hex.c -o sim_hex -DIHEX_TEST -Dtest_main=main
extern "C" {
#endif
+// Load a firmware file, ELF or HEX format, ready for use.
+
+struct elf_firmware_t; // Predeclaration ...
+
+void
+sim_setup_firmware(
+ const char * filename, // Firmware file
+ uint32_t loadBase, // Base of load region
+ struct elf_firmware_t * fp, // Data returned here
+ const char * progname); // For error messages.
+
// parses a hex text string 'src' of at max 'maxlen' characters, decodes it into 'buffer'
int
read_hex_string(
#
-# This makefile takes each "at*" file, extracts it's part name
-# And compiles it into an ELF binary.
-# It also disassembles it for debugging purposes.
+# This makefile takes each "at*" file, extracts its part name
+# and compiles it into an ELF binary.
#
# Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
#
tests_src := ${wildcard test_*.c}
-all: obj axf tst
+all: obj axf hex tst
include ../Makefile.common
axf: ${sources:.c=.axf}
+hex: atmega88_example.hex
${OBJ}/%.tst: tests.c %.c
ifneq ($(E),)
exit $$num_failed
clean: clean-${OBJ}
- rm -f *.axf *.vcd
+ rm -f *.axf *.hex *.vcd
--- /dev/null
+
+#include <string.h>
+
+#include "tests.h"
+
+/* Modified version of test_atmega88_example.c that uses a .hex file. */
+
+int main(int argc, char **argv) {
+ tests_init(argc, argv);
+
+ elf_firmware_t fw = {0};
+ strncpy(fw.mmcu, "atmega88", sizeof fw.mmcu);
+ fw.frequency = 8 * 1000 * 1000;
+
+ static const char *expected =
+ "Read from eeprom 0xdeadbeef -- should be 0xdeadbeef\r\n"
+ "Read from eeprom 0xcafef00d -- should be 0xcafef00d\r\n";
+ tests_assert_uart_receive_fw(&fw, "atmega88_example.hex", 100000,
+ expected, '0');
+
+ tests_success();
+ return 0;
+}
#include "tests.h"
#include "sim_avr.h"
#include "sim_elf.h"
+#include "sim_hex.h"
#include "sim_core.h"
#include "avr_uart.h"
#include <stdio.h>
return avr->state;
}
-avr_t *tests_init_avr(const char *elfname) {
+/* Set-up AVR from an initialised firmware struct. Works with .hex files. */
+
+static avr_t *tests_init_fw(elf_firmware_t *fwp, const char *filename) {
tests_cycle_count = 0;
map_stderr();
- elf_firmware_t fw = {{0}};
- if (elf_read_firmware(elfname, &fw))
- fail("Failed to read ELF firmware \"%s\"", elfname);
- avr_t *avr = avr_make_mcu_by_name(fw.mmcu);
+ sim_setup_firmware(filename, 0, fwp, test_name);
+ avr_t *avr = avr_make_mcu_by_name(fwp->mmcu);
if (!avr)
fail("Creating AVR failed.");
avr_init(avr);
- avr_load_firmware(avr, &fw);
+ avr_load_firmware(avr, fwp);
return avr;
}
+avr_t *tests_init_avr(const char *elfname) {
+ elf_firmware_t fw = {};
+ return tests_init_fw(&fw, elfname);
+}
+
int tests_run_test(avr_t *avr, unsigned long run_usec) {
if (!avr)
fail("Internal test error: avr == NULL in run_test()");
_fail(NULL, 0, "Outputs differ: expected \"%s\", got \"%s\"", expected, buf->str);
}
+void tests_assert_uart_receive_fw(elf_firmware_t *fw,
+ const char *firmware,
+ unsigned long run_usec,
+ const char *expected,
+ char uart) {
+ avr_t *avr = tests_init_fw(fw, firmware);
+
+ tests_assert_uart_receive_avr(avr, run_usec, expected, uart);
+}
+
void tests_assert_uart_receive_avr(avr_t *avr,
unsigned long run_usec,
const char *expected,
init_output_buffer(&buf);
avr_irq_register_notify(
- avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ(uart),
+ avr_io_getirq(avr, AVR_IOCTL_UART_GETIRQ(uart),
UART_IRQ_OUTPUT), buf_output_cb, &buf);
- tests_assert_xxxx_receive_avr(avr, run_usec, &buf, expected);
+ tests_assert_xxxx_receive_avr(avr, run_usec, &buf, expected);
}
void tests_assert_uart_receive(const char *elfname,
char uart) {
avr_t *avr = tests_init_avr(elfname);
- tests_assert_uart_receive_avr(avr,
- run_usec,
- expected,
- uart);
+ tests_assert_uart_receive_avr(avr, run_usec, expected, uart);
}
void tests_assert_register_receive_avr(avr_t *avr,
#define __TESTS_H__
#include "sim_avr.h"
+#include "sim_elf.h"
enum tests_finish_reason {
LJR_CYCLE_TIMER = 1,
unsigned long run_usec,
const char *expected,
avr_io_addr_t reg_addr);
+void tests_assert_uart_receive_fw(elf_firmware_t *fw,
+ const char *firmware,
+ unsigned long run_usec,
+ const char *expected,
+ char uart);
void tests_assert_cycles_at_least(unsigned long n);
void tests_assert_cycles_at_most(unsigned long n);