Commit 6d60bfd4145136b1e9d21083034fd44aa1c09822
authorMichel Pollet <buserror@gmail.com>
Thu, 10 Oct 2013 14:12:31 +0000 (15:12 +0100)
committerMichel Pollet <buserror@gmail.com>
Thu, 10 Oct 2013 14:12:31 +0000 (15:12 +0100)
Now supports an "external" simulation of a pullup/down, this
resets the outgoing IRQ for pins to a default that can be
specified.

Signed-off-by: Michel Pollet <buserror@gmail.com>
2 files changed:
simavr/sim/avr_ioport.c
simavr/sim/avr_ioport.h

index b787d2c68c402b0a0338d0e9c4a9495370425881..d758ecfade7f37f60b4e05a4e8faaa82bcc0ab57 100644 (file)
@@ -35,6 +35,27 @@ static uint8_t avr_ioport_read(struct avr_t * avr, avr_io_addr_t addr, void * pa
        return v;
 }
 
+static void avr_ioport_update_irqs(avr_ioport_t * p)
+{
+       avr_t * avr = p->io.avr;
+       uint8_t ddr = avr->data[p->r_ddr];
+       // Set the PORT value if the pin is marked as output
+       // otherwise, if there is an 'external' pullup, set it
+       // otherwise, if the PORT pin was 1 to indicate an
+       // internal pullup, set that.
+       for (int i = 0; i < 8; i++) {
+               if (ddr & (1 << i))
+                       avr_raise_irq(p->io.irq + i, (avr->data[p->r_port] >> i) & 1);
+               else if (p->external.pull_mask & (1 << i))
+                       avr_raise_irq(p->io.irq + i, (p->external.pull_value >> i) & 1);
+               else if ((avr->data[p->r_port] >> i) & 1)
+                       avr_raise_irq(p->io.irq + i, 1);
+       }
+       uint8_t pin = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr);
+       pin = (pin & ~p->external.pull_mask) | p->external.pull_value;
+       avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, pin);
+}
+
 static void avr_ioport_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
 {
        avr_ioport_t * p = (avr_ioport_t *)param;
@@ -42,10 +63,7 @@ static void avr_ioport_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v,
        avr_core_watch_write(avr, addr, v);
        //      printf("PORT%c(%02x) = %02x (was %02x)\n", p->name, addr, v, oldv);
 
-       // raise the internal IRQ callbacks
-       for (int i = 0; i < 8; i++)
-               avr_raise_irq(p->io.irq + i, (v >> i) & 1);
-       avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v);
+       avr_ioport_update_irqs(p);
 }
 
 /*
@@ -71,13 +89,7 @@ static void avr_ioport_ddr_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t
        avr_raise_irq(p->io.irq + IOPORT_IRQ_DIRECTION_ALL, v);
        avr_core_watch_write(avr, addr, v);
 
-       const uint8_t oldpin = avr->data[p->r_pin];
-       const uint8_t pin = (oldpin & ~v) | (avr->data[p->r_port] & v);
-       avr_core_watch_write(avr, p->r_pin, pin);
-       for (int i = 0; i < 8; i++)
-               if (((oldpin ^ pin) >> i) & 1)
-                       avr_raise_irq(p->io.irq + i, (pin >> i) & 1);
-       avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, pin);
+       avr_ioport_update_irqs(p);
 }
 
 /*
@@ -112,7 +124,7 @@ void avr_ioport_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
 static void avr_ioport_reset(avr_io_t * port)
 {
        avr_ioport_t * p = (avr_ioport_t *)port;
-       for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++) 
+       for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++)
                avr_irq_register_notify(p->io.irq + i, avr_ioport_irq_notify, p);
 }
 
@@ -157,6 +169,15 @@ static int avr_ioport_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_para
                                        *((avr_ioport_state_t*)io_param) = state;
                                res = 0;
                        }
+                       /*
+                        * Set the default IRQ values when pin is set as input
+                        */
+                       if (ctl == AVR_IOCTL_IOPORT_SET_EXTERNAL(p->name)) {
+                               avr_ioport_external_t * m = (avr_ioport_external_t*)io_param;
+                               p->external.pull_mask = m->mask;
+                               p->external.pull_value = m->value;
+                               res = 0;
+                       }
                }
        }
 
@@ -190,7 +211,7 @@ void avr_ioport_init(avr_t * avr, avr_ioport_t * p)
 //             p->name, p->r_pin,
 //             p->name, p->r_ddr,
 //             p->name, p->r_port);
-       
+
        avr_register_io(avr, &p->io);
        avr_register_vector(avr, &p->pcint);
        // allocate this module's IRQ
index c6f5a4b7789ab17cc27dfefb438cb70800bb82e8..32feef8bc07d8a97e5c7adadfd26a71577cb5b12 100644 (file)
@@ -70,6 +70,18 @@ typedef struct avr_ioport_state_t {
 // add port name (uppercase) to get the port state
 #define AVR_IOCTL_IOPORT_GETSTATE(_name) AVR_IOCTL_DEF('i','o','s',(_name))
 
+/*
+ * ioctl used to set default port state when set as input.
+ *
+ */
+typedef struct avr_ioport_external_t {
+       unsigned long name : 7,
+               mask : 8, value : 8;
+} avr_ioport_external_t;
+
+// add port name (uppercase) to set default input pin IRQ values
+#define AVR_IOCTL_IOPORT_SET_EXTERNAL(_name) AVR_IOCTL_DEF('i','o','p',(_name))
+
 /**
  * pin structure
  */
@@ -91,6 +103,15 @@ typedef struct avr_ioport_t {
 
        avr_int_vector_t pcint; // PCINT vector
        avr_io_addr_t r_pcint;          // pcint 8 pins mask
+
+       // this represent the default IRQ value when
+       // the port is set as input.
+       // If the mask is not set, no output value is sent
+       // on the output IRQ. If the mask is set, the specified
+       // value is sent.
+       struct {
+               uint8_t pull_mask, pull_value;
+       } external;
 } avr_ioport_t;
 
 void avr_ioport_init(avr_t * avr, avr_ioport_t * port);