From 51d5f4b07034798845f5d975c6d4df1cc3d0b79f Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Tue, 15 Dec 2009 21:39:49 +0000 Subject: [PATCH] ELF: Redone the .mmcu section The section now uses :tags: that can be parsed regardless of order, size, alignment and so on. Also added tags to allow a firmware to register VCD traces directly from macros placed in the firmware itself. This allows very quick and painless trace generation of any IO register/bit without having to know the real values for the addresses. Signed-off-by: Michel Pollet --- include/avr_mcu_section.h | 87 +++++++++++++++++++++++++++++++------ simavr/sim/run_avr.c | 10 ++--- simavr/sim/sim_elf.c | 90 ++++++++++++++++++++++++++++++++++++++- simavr/sim/sim_elf.h | 13 +++++- 4 files changed, 179 insertions(+), 21 deletions(-) diff --git a/include/avr_mcu_section.h b/include/avr_mcu_section.h index c7a6a2e..eb36512 100644 --- a/include/avr_mcu_section.h +++ b/include/avr_mcu_section.h @@ -23,7 +23,7 @@ #define __AVR_MCU_SECTION_H__ /* - * This structure is used to pass "parameters" to the programmer or the simulator, + * This header is used to pass "parameters" to the programmer or the simulator, * it tags the ELF file with a section that contains parameters about the physical * AVR this was compiled for, including the speed, model, and signature bytes. * @@ -40,20 +40,81 @@ #include -struct avr_mcu_t -{ - uint32_t f_cpu; // avr is little endian - uint32_t reserved; - uint8_t mid[4]; // signature bytes - uint8_t fuse[4]; // optional - char name[16]; +enum { + AVR_MMCU_TAG = 0, + AVR_MMCU_TAG_NAME, + AVR_MMCU_TAG_FREQUENCY, + AVR_MMCU_TAG_LFUSE, + AVR_MMCU_TAG_HFUSE, + AVR_MMCU_TAG_EFUSE, + AVR_MMCU_TAG_SIGNATURE, + AVR_MMCU_TAG_VCD_FILENAME, + AVR_MMCU_TAG_VCD_PERIOD, + AVR_MMCU_TAG_VCD_TRACE, +}; + +#if __AVR__ + +#define _MMCU_ __attribute__((section(".mmcu"))) +struct avr_mmcu_long_t { + uint8_t tag; + uint8_t len; + uint32_t val; } __attribute__((__packed__)); -#define AVR_MCU(_speed, _name) \ -const struct avr_mcu_t _mmcu __attribute__((section(".mmcu"))) = {\ - .f_cpu = _speed, \ - .mid = {SIGNATURE_0, SIGNATURE_1, SIGNATURE_2}, \ - .name = _name,\ +struct avr_mmcu_string_t { + uint8_t tag; + uint8_t len; + char string[]; +} __attribute__((__packed__)); + +struct avr_mmcu_vcd_trace_t { + uint8_t tag; + uint8_t len; + uint8_t mask; + void * what; + char name[]; +} __attribute__((__packed__)); + +#define AVR_MCU_STRING(_tag, _str) \ +const struct avr_mmcu_string_t _##_tag _MMCU_ = {\ + .tag = _tag,\ + .len = sizeof(_str),\ + .string = _str,\ +} + +#define AVR_MCU_LONG(_tag, _val) \ +const struct avr_mmcu_long_t _##_tag _MMCU_ = {\ + .tag = _tag,\ + .len = sizeof(uint32_t),\ + .val = _val,\ } +#define AVR_MCU_BYTE(_tag, _val) \ +const uint8_t _##_tag _MMCU_ = { _tag, 1, _val } + +#define AVR_MCU_VCD_SYMBOL(_name) \ + .tag = AVR_MMCU_TAG_VCD_TRACE, \ + .len = sizeof(struct avr_mmcu_vcd_trace_t) - 2 + sizeof(_name),\ + .name = _name + +// specified the nane and wanted period (usec) for a VCD file +// thid is not mandatory, a default one will be created if +// symbols are declared themselves +#define AVR_MCU_VCD_FILE(_name, _period) \ + AVR_MCU_STRING(AVR_MMCU_TAG_VCD_FILENAME, _name);\ + AVR_MCU_LONG(AVR_MMCU_TAG_VCD_PERIOD, _period) + +/* + * This the has to be used if you want to add other tags to the .mmcu section + * the _mmcu symbol is used as an anchor to make sure it stays linked in. + */ +#define AVR_MCU(_speed, _name) \ + const uint8_t _mmcu[2] _MMCU_ = { AVR_MMCU_TAG, 0 }; \ + AVR_MCU_STRING(AVR_MMCU_TAG_NAME, _name);\ + AVR_MCU_LONG(AVR_MMCU_TAG_FREQUENCY, _speed) + +#endif /* __AVR__ */ + + #endif diff --git a/simavr/sim/run_avr.c b/simavr/sim/run_avr.c index 49c374c..bc1d606 100644 --- a/simavr/sim/run_avr.c +++ b/simavr/sim/run_avr.c @@ -103,15 +103,15 @@ int main(int argc, char *argv[]) elf_read_firmware(argv[argc-1], &f); if (strlen(name)) - strcpy(f.mmcu.name, name); + strcpy(f.mmcu, name); if (f_cpu) - f.mmcu.f_cpu = f_cpu; + f.frequency = f_cpu; - printf("firmware %s f=%d mmcu=%s\n", argv[argc-1], (int)f.mmcu.f_cpu, f.mmcu.name); + printf("firmware %s f=%d mmcu=%s\n", argv[argc-1], (int)f.frequency, f.mmcu); - avr_t * avr = avr_make_mcu_by_name(f.mmcu.name); + avr_t * avr = avr_make_mcu_by_name(f.mmcu); if (!avr) { - fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu.name); + fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu); exit(1); } avr_init(avr); diff --git a/simavr/sim/sim_elf.c b/simavr/sim/sim_elf.c index 164db2d..4bd617a 100644 --- a/simavr/sim/sim_elf.c +++ b/simavr/sim/sim_elf.c @@ -33,11 +33,12 @@ #include #include "sim_elf.h" +#include "sim_vcd_file.h" #include "avr_eeprom.h" void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware) { - avr->frequency = firmware->mmcu.f_cpu; + avr->frequency = firmware->frequency; #if CONFIG_SIMAVR_TRACE avr->codeline = firmware->codeline; #endif @@ -47,6 +48,91 @@ void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware) avr_eeprom_desc_t d = { .ee = firmware->eeprom, .offset = 0, .size = firmware->eesize }; avr_ioctl(avr, AVR_IOCTL_EEPROM_SET, &d); } + + if (firmware->tracecount == 0) + return; + avr->vcd = malloc(sizeof(*avr->vcd)); + memset(avr->vcd, 0, sizeof(*avr->vcd)); + avr_vcd_init(avr, + firmware->tracename[0] ? firmware->tracename: "gtkwave_trace.vcd", + avr->vcd, + firmware->traceperiod >= 5 ? firmware->traceperiod : 5); + + printf("Creating VCD trace file '%s'\n", avr->vcd->filename); + for (int ti = 0; ti < firmware->tracecount; ti++) { + if (firmware->trace[ti].mask == 0xff || firmware->trace[ti].mask == 0) { + // easy one + avr_irq_t * all = avr_iomem_getirq(avr, firmware->trace[ti].addr, AVR_IOMEM_IRQ_ALL); + if (!all) { + printf("%s: unable to attach trace to address %04x\n", + __FUNCTION__, firmware->trace[ti].addr); + } else { + avr_vcd_add_signal(avr->vcd, all, 8, firmware->trace[ti].name); + } + } else { + int count = 0; + for (int bi = 0; bi < 8; bi++) + if (firmware->trace[ti].mask & (1 << bi)) + count++; + for (int bi = 0; bi < 8; bi++) + if (firmware->trace[ti].mask & (1 << bi)) { + avr_irq_t * bit = avr_iomem_getirq(avr, firmware->trace[ti].addr, bi); + if (!bit) { + printf("%s: unable to attach trace to address %04x\n", + __FUNCTION__, firmware->trace[ti].addr); + break; + } + + if (count == 1) { + avr_vcd_add_signal(avr->vcd, bit, 1, firmware->trace[ti].name); + break; + } + char comp[128]; + sprintf(comp, "%s.%d", firmware->trace[ti].name, bi); + avr_vcd_add_signal(avr->vcd, bit, 1, firmware->trace[ti].name); + } + } + } + avr_vcd_start(avr->vcd); +} + +static void elf_parse_mmcu_section(elf_firmware_t * firmware, uint8_t * src, uint32_t size) +{ + while (size) { + uint8_t tag = *src++; + uint8_t ts = *src++; + int next = size > 2 + ts ? 2 + ts : size; + printf("elf_parse_mmcu_section %d, %d / %d\n", tag, ts, size); + switch (tag) { + case AVR_MMCU_TAG_FREQUENCY: + firmware->frequency = + src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + break; + case AVR_MMCU_TAG_NAME: + strcpy(firmware->mmcu, src); + break; + case AVR_MMCU_TAG_VCD_TRACE: { + uint8_t mask = src[0]; + uint16_t addr = src[1] | (src[2] << 8); + char * name = src + 3; + printf("AVR_MMCU_TAG_VCD_TRACE %04x:%02x - %s\n", addr, mask, name); + firmware->trace[firmware->tracecount].mask = mask; + firmware->trace[firmware->tracecount].addr = addr; + strncpy(firmware->trace[firmware->tracecount].name, name, + sizeof(firmware->trace[firmware->tracecount].name)); + firmware->tracecount++; + } break; + case AVR_MMCU_TAG_VCD_FILENAME: { + strcpy(firmware->tracename, src); + } break; + case AVR_MMCU_TAG_VCD_PERIOD: { + firmware->traceperiod = + src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + } break; + } + size -= next; + src += next - 2; // already incremented + } } int elf_read_firmware(const char * file, elf_firmware_t * firmware) @@ -103,7 +189,7 @@ int elf_read_firmware(const char * file, elf_firmware_t * firmware) firmware->bsssize = s->d_size; } else if (!strcmp(name, ".mmcu")) { Elf_Data *s = elf_getdata(scn, NULL); - firmware->mmcu = *((struct avr_mcu_t*)s->d_buf); + elf_parse_mmcu_section(firmware, s->d_buf, s->d_size); //printf("%s: avr_mcu_t size %ld / read %ld\n", __FUNCTION__, sizeof(struct avr_mcu_t), s->d_size); // avr->frequency = f_cpu; } diff --git a/simavr/sim/sim_elf.h b/simavr/sim/sim_elf.h index bc61613..f12c8f7 100644 --- a/simavr/sim/sim_elf.h +++ b/simavr/sim/sim_elf.h @@ -31,7 +31,18 @@ #include "sim_avr.h" typedef struct elf_firmware_t { - struct avr_mcu_t mmcu; + char mmcu[64]; + uint32_t frequency; + + char tracename[128]; // trace filename + uint32_t traceperiod; + int tracecount; + struct { + uint8_t mask; + uint16_t addr; + char name[64]; + } trace[32]; + uint8_t * flash; uint32_t flashsize; uint32_t datasize; -- 2.20.1