Commit 2c407d6d22473809a431a55b1c6877015c3c9814
authorMichel Pollet <buserror@gmail.com>
Thu, 10 Oct 2013 14:14:17 +0000 (15:14 +0100)
committerMichel Pollet <buserror@gmail.com>
Thu, 10 Oct 2013 14:14:17 +0000 (15:14 +0100)
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 <buserror@gmail.com>
3 files changed:
simavr/sim/avr/avr_mcu_section.h
simavr/sim/sim_elf.c
simavr/sim/sim_elf.h

index fca11c63c9c06e0f543757ce3c8d23389dffc91a..ddef0b64e1a2c3f60fb4472a77bc5ab10fb66d8c 100644 (file)
@@ -1,7 +1,7 @@
 /*
        avr_mcu_section.h
 
-       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+       Copyright 2008-2013 Michel Pollet <buserror@gmail.com>
 
        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
index 37cd653462096462b622dd28e7543a8e04ed6126..68fe2e2c685c3aebd9c12cce0d478395f24b68b5 100644 (file)
@@ -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);
index d91b0e5d93669928215e13a6dd7a752c4574fbcd..30b399c24724c401b376025e099c7e7ccbedd2c2 100644 (file)
@@ -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;