Commit 51d5f4b07034798845f5d975c6d4df1cc3d0b79f
authorMichel Pollet <buserror@gmail.com>
Tue, 15 Dec 2009 21:39:49 +0000 (21:39 +0000)
committerMichel Pollet <buserror@gmail.com>
Tue, 15 Dec 2009 21:39:49 +0000 (21:39 +0000)
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 <buserror@gmail.com>
4 files changed:
include/avr_mcu_section.h
simavr/sim/run_avr.c
simavr/sim/sim_elf.c
simavr/sim/sim_elf.h

index c7a6a2ee9f78b7118a93c12686c45fa755dac675..eb36512bdc6f09acb6946631a0bda8b1b0e39698 100644 (file)
@@ -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.
  *
 
 #include <stdint.h>
 
-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
index 49c374c8464695c7375f1bfbac780080e5b22477..bc1d606ec8917ffc3694c441737b6f0e20ffaa87 100644 (file)
@@ -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);
index 164db2d8324b78b44b4bf7d71b5f0da1174b901f..4bd617a1e963825a62e9075a95cf45e5119995a3 100644 (file)
 #include <gelf.h>
 
 #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;
                }
index bc616138ad66aa6f3a2fbf662e69840f2a795c2b..f12c8f7f2b4ea1bfa0df4d2a92462f3785889cd3 100644 (file)
 #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;