4 Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
6 This file is part of simavr.
8 simavr is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 simavr is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with simavr. If not, see <http://www.gnu.org/licenses/>.
23 #include "avr_ioport.h"
25 static uint8_t avr_ioport_read(struct avr_t * avr, avr_io_addr_t addr, void * param)
27 avr_ioport_t * p = (avr_ioport_t *)param;
28 uint8_t ddr = avr->data[p->r_ddr];
29 uint8_t v = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr);
31 // made to trigger potential watchpoints
32 v = avr_core_watch_read(avr, addr);
33 // printf("** PIN%c(%02x) = %02x\n", p->name, addr, v);
38 static void avr_ioport_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
40 avr_ioport_t * p = (avr_ioport_t *)param;
41 uint8_t oldv = avr->data[addr];
43 avr_core_watch_write(avr, addr, v);
45 // printf("PORT%c(%02x) = %02x (was %02x)\n", p->name, addr, v, oldv);
48 // raise the internal IRQ callbacks
49 for (int i = 0; i < 8; i++)
51 avr_raise_irq(p->io.irq + i, (v >> i) & 1);
52 avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v);
57 * This is a reasonably new behaviour for the io-ports. Writing 1's to the PIN register
58 * toggles the PORT equivalent bit (regardless of direction
60 static void avr_ioport_pin_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
62 avr_ioport_t * p = (avr_ioport_t *)param;
64 avr_ioport_write(avr, p->r_port, avr->data[p->r_port] ^ v, param);
68 * this is our "main" pin change callback, it can be triggered by either the
69 * AVR code, or any external piece of code that see fit to do it.
70 * Either way, this will raise pin change interrupts, if needed
72 void avr_ioport_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
74 avr_ioport_t * p = (avr_ioport_t *)param;
75 avr_t * avr = p->io.avr;
77 int output = value & 0x100;
79 uint8_t mask = 1 << irq->irq;
80 // set the real PIN bit. ddr doesn't matter here as it's masked when read.
81 avr->data[p->r_pin] &= ~mask;
83 avr->data[p->r_pin] |= mask;
85 if (output) // if the IRQ was marked as Output, also do the IO write
86 avr_ioport_write(avr, p->r_port, (avr->data[p->r_port] & ~mask) | (value ? mask : 0), p);
89 // if the pcint bit is on, try to raise it
90 int raise = avr->data[p->r_pcint] & mask;
92 avr_raise_interrupt(avr, &p->pcint);
96 static void avr_ioport_reset(avr_io_t * port)
98 avr_ioport_t * p = (avr_ioport_t *)port;
99 for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++)
100 avr_irq_register_notify(p->io.irq + i, avr_ioport_irq_notify, p);
103 static int avr_ioport_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
105 avr_ioport_t * p = (avr_ioport_t *)port;
109 case AVR_IOCTL_IOPORT_GETIRQ_REGBIT: {
110 avr_ioport_getirq_t * r = (avr_ioport_getirq_t*)io_param;
112 if (r->bit.reg == p->r_port || r->bit.reg == p->r_pin || r->bit.reg == p->r_ddr) {
113 // it's us ! check the special case when the "all pins" irq is requested
115 if (r->bit.mask == 0xff)
116 r->irq[o++] = &p->io.irq[IOPORT_IRQ_PIN_ALL];
118 // otherwise fil up the ones needed
119 for (int bi = 0; bi < 8; bi++)
120 if (r->bit.mask & (1 << bi))
121 r->irq[o++] = &p->io.irq[r->bit.bit + bi];
133 static avr_io_t _io = {
135 .reset = avr_ioport_reset,
136 .ioctl = avr_ioport_ioctl,
139 void avr_ioport_init(avr_t * avr, avr_ioport_t * p)
142 // printf("%s PIN%c 0x%02x DDR%c 0x%02x PORT%c 0x%02x\n", __FUNCTION__,
143 // p->name, p->r_pin,
144 // p->name, p->r_ddr,
145 // p->name, p->r_port);
147 // allocate this module's IRQ
148 p->io.irq_count = IOPORT_IRQ_COUNT;
149 p->io.irq = avr_alloc_irq(0, p->io.irq_count);
150 p->io.irq_ioctl_get = AVR_IOCTL_IOPORT_GETIRQ(p->name);
152 avr_register_io(avr, &p->io);
153 avr_register_vector(avr, &p->pcint);
155 avr_register_io_write(avr, p->r_port, avr_ioport_write, p);
156 avr_register_io_read(avr, p->r_pin, avr_ioport_read, p);
157 avr_register_io_write(avr, p->r_pin, avr_ioport_pin_write, p);