Commit 3b09cfd99518d3777d0380b4425c778f4b84ed83
authorga <ga@oldell.fish>
Tue, 24 Aug 2021 08:00:51 +0000 (09:00 +0100)
committerga <ga@oldell.fish>
Thu, 12 May 2022 07:56:41 +0000 (08:56 +0100)
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.

7 files changed:
simavr/sim/run_avr.c
simavr/sim/sim_hex.c
simavr/sim/sim_hex.h
tests/Makefile
tests/test_atmega88_hex.c [new file with mode: 0644]
tests/tests.c
tests/tests.h

index a4f79e7bce5e8b20f200ed43a41f33d3ed84606c..dfa6fcecb07456eeeb8229c3b8731a81a6423982 100644 (file)
@@ -118,15 +118,19 @@ main(
                } 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];
@@ -222,45 +226,14 @@ main(
                } 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)
index 05fd65d7eeb786c7c899db8ef980e900440e9f75..fea67c48a5eec12ff3cb973dbaf2a91106559c52 100644 (file)
@@ -23,6 +23,7 @@
 #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)
@@ -190,7 +191,79 @@ read_ihex_file(
        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
index 67ecc775e9159ebc7a929728b72b1b833ec0f6b1..e3a1d1fd598b2bf1b8d3b078d66dd3b03b0d2c17 100644 (file)
 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(
index 38f492cc5e5a4b170129f7605d2377fdc50aed11..0b2728432261deb58eddde2808f6174790716798 100644 (file)
@@ -1,7 +1,6 @@
 #
-# 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>
 #
@@ -28,7 +27,7 @@ IPATH                 += ${simavr}/simavr/sim
 
 tests_src      := ${wildcard test_*.c}
 
-all: obj axf tst
+all: obj axf hex tst
 
 include ../Makefile.common
 
@@ -36,6 +35,7 @@ tst: ${patsubst %.c, ${OBJ}/%.tst, ${tests_src}}
 
 axf: ${sources:.c=.axf}
 
+hex: atmega88_example.hex
 
 ${OBJ}/%.tst: tests.c %.c
 ifneq ($(E),)
@@ -58,4 +58,4 @@ run_tests: all
        exit $$num_failed
 
 clean: clean-${OBJ}
-       rm -f *.axf *.vcd
+       rm -f *.axf *.hex *.vcd
diff --git a/tests/test_atmega88_hex.c b/tests/test_atmega88_hex.c
new file mode 100644 (file)
index 0000000..f65789a
--- /dev/null
@@ -0,0 +1,23 @@
+
+#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;
+}
index db18153e0f01b84186935182a8b2e48b1d370650..5000cf6584ac6a0a3f4523ad202317531ae34ec0 100644 (file)
@@ -1,6 +1,7 @@
 #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>
@@ -99,21 +100,26 @@ static int my_avr_run(avr_t * avr)
        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()");
@@ -208,6 +214,16 @@ static void tests_assert_xxxx_receive_avr(avr_t                *avr,
                _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,
@@ -216,9 +232,9 @@ void tests_assert_uart_receive_avr(avr_t *avr,
        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,
@@ -227,10 +243,7 @@ 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,
index e378f837b3aa771b0d37af97afeafd5452497c7e..cdbae2640ec9adc55df6e01050644b6d6e397dab 100644 (file)
@@ -2,6 +2,7 @@
 #define __TESTS_H__
 
 #include "sim_avr.h"
+#include "sim_elf.h"
 
 enum tests_finish_reason {
        LJR_CYCLE_TIMER = 1,
@@ -40,6 +41,11 @@ void tests_assert_register_receive_avr(avr_t         *avr,
                                        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);