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, uint8_t addr, void * param)
27 avr_ioport_t * p = (avr_ioport_t *)param;
28 uint8_t v = avr->data[addr];
30 if (addr == p->r_pin) {
31 uint8_t ddr = avr->data[p->r_ddr];
32 uint8_t v = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr);
34 // made to trigger potential watchpoints
35 v = avr_core_watch_read(avr, addr);
36 // printf("** PIN%c(%02x) = %02x\n", p->name, addr, v);
41 static void avr_ioport_write(struct avr_t * avr, uint8_t addr, uint8_t v, void * param)
43 avr_ioport_t * p = (avr_ioport_t *)param;
44 uint8_t oldv = avr->data[addr];
46 if (addr == p->r_port) {
48 avr_core_watch_write(avr, addr, v);
50 // printf("PORT%c(%02x) = %02x (was %02x)\n", p->name, addr, v, oldv);
53 // raise the internal IRQ callbacks
54 for (int i = 0; i < 8; i++)
56 avr_raise_irq(p->io.irq + i, (v >> i) & 1);
57 avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v);
63 * this is our "main" pin change callback, it can be triggered by either the
64 * AVR code, or any external piece of code that see fit to do it.
65 * Either way, this will raise pin change interrupts, if needed
67 void avr_ioport_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
69 avr_ioport_t * p = (avr_ioport_t *)param;
70 avr_t * avr = p->io.avr;
72 // printf("pcint port%c pcint %02x:%02x\n", p->name, p->r_pcint, avr->data[p->r_pcint]);
74 uint8_t mask = 1 << irq->irq;
75 // set the real PIN bit. ddr doesn't matter here as it's masked when read.
76 avr->data[p->r_pin] &= ~mask;
78 avr->data[p->r_pin] |= mask;
79 // if the pcint bit is on, try to raise it
80 int raise = avr->data[p->r_pcint] & mask;
82 avr_raise_interrupt(avr, &p->pcint);
86 static void avr_ioport_reset(avr_io_t * port)
88 avr_ioport_t * p = (avr_ioport_t *)port;
89 for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++)
90 avr_irq_register_notify(p->io.irq + i, avr_ioport_irq_notify, p);
93 static avr_io_t _io = {
95 .reset = avr_ioport_reset,
98 void avr_ioport_init(avr_t * avr, avr_ioport_t * p)
101 // printf("%s PIN%c 0x%02x DDR%c 0x%02x PORT%c 0x%02x\n", __FUNCTION__,
102 // p->name, p->r_pin,
103 // p->name, p->r_ddr,
104 // p->name, p->r_port);
106 // allocate this module's IRQ
107 p->io.irq_count = IOPORT_IRQ_COUNT;
108 p->io.irq = avr_alloc_irq(0, p->io.irq_count);
109 p->io.irq_ioctl_get = AVR_IOCTL_IOPORT_GETIRQ(p->name);
111 avr_register_io(avr, &p->io);
112 avr_register_vector(avr, &p->pcint);
114 avr_register_io_write(avr, p->r_port, avr_ioport_write, p);
115 avr_register_io_read(avr, p->r_pin, avr_ioport_read, p);