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 a the callback for the DDR register. There is nothing much to do here, apart
69 * from triggering an IRQ in case any 'client' code is interested in the information.
71 static void avr_ioport_ddr_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
73 avr_ioport_t * p = (avr_ioport_t *)param;
75 avr_raise_irq(p->io.irq + IOPORT_IRQ_DIRECTION_ALL, v);
76 avr_core_watch_write(avr, addr, v);
80 * this is our "main" pin change callback, it can be triggered by either the
81 * AVR code, or any external piece of code that see fit to do it.
82 * Either way, this will raise pin change interrupts, if needed
84 void avr_ioport_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
86 avr_ioport_t * p = (avr_ioport_t *)param;
87 avr_t * avr = p->io.avr;
89 int output = value & 0x100;
91 uint8_t mask = 1 << irq->irq;
92 // set the real PIN bit. ddr doesn't matter here as it's masked when read.
93 avr->data[p->r_pin] &= ~mask;
95 avr->data[p->r_pin] |= mask;
97 if (output) // if the IRQ was marked as Output, also do the IO write
98 avr_ioport_write(avr, p->r_port, (avr->data[p->r_port] & ~mask) | (value ? mask : 0), p);
101 // if the pcint bit is on, try to raise it
102 int raise = avr->data[p->r_pcint] & mask;
104 avr_raise_interrupt(avr, &p->pcint);
108 static void avr_ioport_reset(avr_io_t * port)
110 avr_ioport_t * p = (avr_ioport_t *)port;
111 for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++)
112 avr_irq_register_notify(p->io.irq + i, avr_ioport_irq_notify, p);
115 static int avr_ioport_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param)
117 avr_ioport_t * p = (avr_ioport_t *)port;
118 avr_t * avr = p->io.avr;
122 case AVR_IOCTL_IOPORT_GETIRQ_REGBIT: {
123 avr_ioport_getirq_t * r = (avr_ioport_getirq_t*)io_param;
125 if (r->bit.reg == p->r_port || r->bit.reg == p->r_pin || r->bit.reg == p->r_ddr) {
126 // it's us ! check the special case when the "all pins" irq is requested
128 if (r->bit.mask == 0xff)
129 r->irq[o++] = &p->io.irq[IOPORT_IRQ_PIN_ALL];
131 // otherwise fil up the ones needed
132 for (int bi = 0; bi < 8; bi++)
133 if (r->bit.mask & (1 << bi))
134 r->irq[o++] = &p->io.irq[r->bit.bit + bi];
143 * Return the port state if the IOCTL matches us.
145 if (ctl == AVR_IOCTL_IOPORT_GETSTATE(p->name)) {
146 avr_ioport_state_t state = {
148 .port = avr->data[p->r_port],
149 .ddr = avr->data[p->r_ddr],
150 .pin = avr->data[p->r_pin],
153 *((avr_ioport_state_t*)io_param) = state;
162 static avr_io_t _io = {
164 .reset = avr_ioport_reset,
165 .ioctl = avr_ioport_ioctl,
168 void avr_ioport_init(avr_t * avr, avr_ioport_t * p)
171 // printf("%s PIN%c 0x%02x DDR%c 0x%02x PORT%c 0x%02x\n", __FUNCTION__,
172 // p->name, p->r_pin,
173 // p->name, p->r_ddr,
174 // p->name, p->r_port);
176 avr_register_io(avr, &p->io);
177 avr_register_vector(avr, &p->pcint);
178 // allocate this module's IRQ
179 avr_io_setirqs(&p->io, AVR_IOCTL_IOPORT_GETIRQ(p->name), IOPORT_IRQ_COUNT, NULL);
181 avr_register_io_write(avr, p->r_port, avr_ioport_write, p);
182 avr_register_io_read(avr, p->r_pin, avr_ioport_read, p);
183 avr_register_io_write(avr, p->r_pin, avr_ioport_pin_write, p);
184 avr_register_io_write(avr, p->r_ddr, avr_ioport_ddr_write, p);