From: Michel Pollet Date: Thu, 10 Oct 2013 14:14:17 +0000 (+0100) Subject: elf: Added support for external pullup/down X-Git-Tag: v1.1~3 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=2c407d6d22473809a431a55b1c6877015c3c9814;p=sx%2Fsimavr.git elf: Added support for external pullup/down Added a new "mmcu" section to allow firmwares to specify what IRQ value should be set when a pin is marked as input Signed-off-by: Michel Pollet --- diff --git a/simavr/sim/avr/avr_mcu_section.h b/simavr/sim/avr/avr_mcu_section.h index fca11c6..ddef0b6 100644 --- a/simavr/sim/avr/avr_mcu_section.h +++ b/simavr/sim/avr/avr_mcu_section.h @@ -1,7 +1,7 @@ /* avr_mcu_section.h - Copyright 2008, 2009 Michel Pollet + Copyright 2008-2013 Michel Pollet This file is part of simavr. @@ -58,8 +58,9 @@ enum { AVR_MMCU_TAG_SIMAVR_COMMAND, AVR_MMCU_TAG_SIMAVR_CONSOLE, AVR_MMCU_TAG_VCD_FILENAME, - AVR_MMCU_TAG_VCD_PERIOD, + AVR_MMCU_TAG_VCD_PERIOD, AVR_MMCU_TAG_VCD_TRACE, + AVR_MMCU_TAG_PORT_EXTERNAL_PULL, }; enum { @@ -75,13 +76,13 @@ enum { struct avr_mmcu_long_t { uint8_t tag; uint8_t len; - uint32_t val; + uint32_t val; } __attribute__((__packed__)); struct avr_mmcu_string_t { uint8_t tag; uint8_t len; - char string[]; + char string[]; } __attribute__((__packed__)); struct avr_mmcu_addr_t { @@ -95,7 +96,7 @@ struct avr_mmcu_vcd_trace_t { uint8_t len; uint8_t mask; void * what; - char name[]; + char name[]; } __attribute__((__packed__)); #define AVR_MCU_STRING(_tag, _str) \ @@ -169,6 +170,19 @@ struct avr_mmcu_vcd_trace_t { .len = sizeof(void *),\ .what = (void*)_register, \ } +/*! + * Allows the firmware to hint simavr as to wether there are external + * pullups/down on PORT pins. It helps if the firmware uses "open drain" + * pins by toggling the DDR pins to switch between an output state and + * a "default" state. + * The value passed here will be output on the PORT IRQ when the DDR + * pin is set to input again + */ +#define AVR_MCU_EXTERNAL_PORT_PULL(_port, _mask, _val) \ + AVR_MCU_LONG(AVR_MMCU_TAG_PORT_EXTERNAL_PULL, \ + (((unsigned long)(_port) << 16) | \ + ((unsigned long)(_mask) << 8) | \ + (_val))); /*! * This tag allows you to specify the voltages used by your board diff --git a/simavr/sim/sim_elf.c b/simavr/sim/sim_elf.c index 37cd653..68fe2e2 100644 --- a/simavr/sim/sim_elf.c +++ b/simavr/sim/sim_elf.c @@ -35,6 +35,7 @@ #include "sim_elf.h" #include "sim_vcd_file.h" #include "avr_eeprom.h" +#include "avr_ioport.h" #ifndef O_BINARY #define O_BINARY 0 @@ -57,7 +58,7 @@ void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware) for (int i = 0; i < firmware->symbolcount; i++) if (!(firmware->symbol[i]->addr >> 20)) // code address - avr->trace_data->codeline[firmware->symbol[i]->addr >> 1] = + avr->trace_data->codeline[firmware->symbol[i]->addr >> 1] = firmware->symbol[i]; // "spread" the pointers for known symbols forward avr_symbol_t * last = NULL; @@ -75,7 +76,18 @@ 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); } - + // load the default pull up/down values for ports + for (int i = 0; i < 8; i++) + if (firmware->external_state[i].port == 0) + break; + else { + avr_ioport_external_t e = { + .name = firmware->external_state[i].port, + .mask = firmware->external_state[i].mask, + .value = firmware->external_state[i].value, + }; + avr_ioctl(avr, AVR_IOCTL_IOPORT_SET_EXTERNAL(e.name), &e); + } avr_set_command_register(avr, firmware->command_register_addr); avr_set_console_register(avr, firmware->console_register_addr); @@ -85,11 +97,11 @@ void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware) return; avr->vcd = malloc(sizeof(*avr->vcd)); memset(avr->vcd, 0, sizeof(*avr->vcd)); - avr_vcd_init(avr, + avr_vcd_init(avr, firmware->tracename[0] ? firmware->tracename: "gtkwave_trace.vcd", avr->vcd, firmware->traceperiod >= 1000 ? firmware->traceperiod : 1000); - + AVR_LOG(avr, LOG_TRACE, "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) { @@ -120,14 +132,14 @@ void avr_load_firmware(avr_t * avr, elf_firmware_t * firmware) __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_add_signal(avr->vcd, bit, 1, firmware->trace[ti].name); } } } @@ -151,7 +163,7 @@ static void elf_parse_mmcu_section(elf_firmware_t * firmware, uint8_t * src, uin break; case AVR_MMCU_TAG_NAME: strcpy(firmware->mmcu, (char*)src); - break; + break; case AVR_MMCU_TAG_VCC: firmware->vcc = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); @@ -164,6 +176,19 @@ static void elf_parse_mmcu_section(elf_firmware_t * firmware, uint8_t * src, uin firmware->aref = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); break; + case AVR_MMCU_TAG_PORT_EXTERNAL_PULL: { + for (int i = 0; i < 8; i++) + if (!firmware->external_state[i].port) { + firmware->external_state[i].port = src[2]; + firmware->external_state[i].mask = src[1]; + firmware->external_state[i].value = src[0]; + AVR_LOG(NULL, LOG_TRACE, "AVR_MMCU_TAG_PORT_EXTERNAL_PULL[%d] %c:%02x:%02x\n", + i, firmware->external_state[i].port, + firmware->external_state[i].mask, + firmware->external_state[i].value); + break; + } + } break; case AVR_MMCU_TAG_VCD_TRACE: { uint8_t mask = src[0]; uint16_t addr = src[1] | (src[2] << 8); @@ -171,7 +196,7 @@ static void elf_parse_mmcu_section(elf_firmware_t * firmware, uint8_t * src, uin AVR_LOG(NULL, LOG_TRACE, "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, + strncpy(firmware->trace[firmware->tracecount].name, name, sizeof(firmware->trace[firmware->tracecount].name)); firmware->tracecount++; } break; @@ -208,7 +233,7 @@ int elf_read_firmware(const char * file, elf_firmware_t * firmware) return -1; } - Elf_Data *data_data = NULL, + Elf_Data *data_data = NULL, *data_text = NULL, *data_ee = NULL; /* Data Descriptor */ @@ -266,8 +291,8 @@ int elf_read_firmware(const char * file, elf_firmware_t * firmware) gelf_getsym(edata, i, &sym); // print out the value and size - if (ELF32_ST_BIND(sym.st_info) == STB_GLOBAL || - ELF32_ST_TYPE(sym.st_info) == STT_FUNC || + if (ELF32_ST_BIND(sym.st_info) == STB_GLOBAL || + ELF32_ST_TYPE(sym.st_info) == STT_FUNC || ELF32_ST_TYPE(sym.st_info) == STT_OBJECT) { const char * name = elf_strptr(elf, shdr.sh_link, sym.st_name); @@ -276,9 +301,9 @@ int elf_read_firmware(const char * file, elf_firmware_t * firmware) s->addr = sym.st_value; if (!(firmware->symbolcount % 8)) firmware->symbol = realloc( - firmware->symbol, + firmware->symbol, (firmware->symbolcount + 8) * sizeof(firmware->symbol[0])); - + // insert new element, keep the array sorted int insert = -1; for (int si = 0; si < firmware->symbolcount && insert == -1; si++) @@ -287,10 +312,10 @@ int elf_read_firmware(const char * file, elf_firmware_t * firmware) if (insert == -1) insert = firmware->symbolcount; else - memmove(firmware->symbol + insert + 1, + memmove(firmware->symbol + insert + 1, firmware->symbol + insert, (firmware->symbolcount - insert) * sizeof(firmware->symbol[0])); - firmware->symbol[insert] = s; + firmware->symbol[insert] = s; firmware->symbolcount++; } } @@ -302,7 +327,7 @@ int elf_read_firmware(const char * file, elf_firmware_t * firmware) (data_text ? data_text->d_size : 0) + (data_data ? data_data->d_size : 0); firmware->flash = malloc(firmware->flashsize); - + // using unsigned int for output, since there is no AVR with 4GB if (data_text) { // hdump("code", data_text->d_buf, data_text->d_size); diff --git a/simavr/sim/sim_elf.h b/simavr/sim/sim_elf.h index d91b0e5..30b399c 100644 --- a/simavr/sim/sim_elf.h +++ b/simavr/sim/sim_elf.h @@ -32,7 +32,7 @@ extern "C" { #define ELF_SYMBOLS 1 #endif -/* these are the addresses the gnu linker uses to +/* these are the addresses the gnu linker uses to * "fake" a non-Harvard addressing space for the AVR */ #define AVR_SEGMENT_OFFSET_FLASH 0 @@ -53,7 +53,12 @@ typedef struct elf_firmware_t { uint16_t addr; char name[64]; } trace[32]; - + + struct { + char port; + uint8_t mask, value; + } external_state[8]; + // register to listen to for commands from the firmware uint16_t command_register_addr; uint16_t console_register_addr;