From: ga Date: Tue, 24 Aug 2021 08:00:51 +0000 (+0100) Subject: Pull the .hex loading code out of run_avr.c and make it available as X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=3b09cfd99518d3777d0380b4425c778f4b84ed83;p=sx%2Fsimavr.git Pull the .hex loading code out of run_avr.c and make it available as 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. --- diff --git a/simavr/sim/run_avr.c b/simavr/sim/run_avr.c index a4f79e7..dfa6fce 100644 --- a/simavr/sim/run_avr.c +++ b/simavr/sim/run_avr.c @@ -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) diff --git a/simavr/sim/sim_hex.c b/simavr/sim/sim_hex.c index 05fd65d..fea67c4 100644 --- a/simavr/sim/sim_hex.c +++ b/simavr/sim/sim_hex.c @@ -23,6 +23,7 @@ #include #include #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 diff --git a/simavr/sim/sim_hex.h b/simavr/sim/sim_hex.h index 67ecc77..e3a1d1f 100644 --- a/simavr/sim/sim_hex.h +++ b/simavr/sim/sim_hex.h @@ -30,6 +30,17 @@ 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( diff --git a/tests/Makefile b/tests/Makefile index 38f492c..0b27284 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -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 # @@ -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 index 0000000..f65789a --- /dev/null +++ b/tests/test_atmega88_hex.c @@ -0,0 +1,23 @@ + +#include + +#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; +} diff --git a/tests/tests.c b/tests/tests.c index db18153..5000cf6 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -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 @@ -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, diff --git a/tests/tests.h b/tests/tests.h index e378f83..cdbae26 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -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);