#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
#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
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)
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;
}