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 & AVR_IOPORT_OUTPUT;
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 fill 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 const char * irq_names[IOPORT_IRQ_COUNT] = {
163 [IOPORT_IRQ_PIN0] = "=pin0",
164 [IOPORT_IRQ_PIN1] = "=pin1",
165 [IOPORT_IRQ_PIN2] = "=pin2",
166 [IOPORT_IRQ_PIN3] = "=pin3",
167 [IOPORT_IRQ_PIN4] = "=pin4",
168 [IOPORT_IRQ_PIN5] = "=pin5",
169 [IOPORT_IRQ_PIN6] = "=pin6",
170 [IOPORT_IRQ_PIN7] = "=pin7",
171 [IOPORT_IRQ_PIN_ALL] = "=all",
172 [IOPORT_IRQ_DIRECTION_ALL] = ">ddr",
175 static avr_io_t _io = {
177 .reset = avr_ioport_reset,
178 .ioctl = avr_ioport_ioctl,
179 .irq_names = irq_names,
182 void avr_ioport_init(avr_t * avr, avr_ioport_t * p)
185 // printf("%s PIN%c 0x%02x DDR%c 0x%02x PORT%c 0x%02x\n", __FUNCTION__,
186 // p->name, p->r_pin,
187 // p->name, p->r_ddr,
188 // p->name, p->r_port);
190 avr_register_io(avr, &p->io);
191 avr_register_vector(avr, &p->pcint);
192 // allocate this module's IRQ
193 avr_io_setirqs(&p->io, AVR_IOCTL_IOPORT_GETIRQ(p->name), IOPORT_IRQ_COUNT, NULL);
195 avr_register_io_write(avr, p->r_port, avr_ioport_write, p);
196 avr_register_io_read(avr, p->r_pin, avr_ioport_read, p);
197 avr_register_io_write(avr, p->r_pin, avr_ioport_pin_write, p);
198 avr_register_io_write(avr, p->r_ddr, avr_ioport_ddr_write, p);