4 Copyright 2008-2012 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/>.
27 #include "sim_interrupts.h"
31 // modulo a cursor value on the pending interrupt fifo
32 #define INT_FIFO_SIZE (sizeof(table->pending) / sizeof(avr_int_vector_t *))
33 #define INT_FIFO_MOD(_v) ((_v) & (INT_FIFO_SIZE - 1))
39 avr_int_table_p table = &avr->interrupts;
40 memset(table, 0, sizeof(*table));
46 avr_int_vector_t * vector)
51 avr_int_table_p table = &avr->interrupts;
53 vector->irq.irq = vector->vector;
54 table->vector[table->vector_count++] = vector;
56 printf("%s register vector %d (enabled %04x:%d)\n", __FUNCTION__, vector->vector, vector->enable.reg, vector->enable.bit);
58 if (!vector->enable.reg)
59 AVR_LOG(avr, LOG_WARNING, "INT: avr_register_vector: No 'enable' bit on vector %d !\n", vector->vector);
63 avr_has_pending_interrupts(
66 avr_int_table_p table = &avr->interrupts;
67 return table->pending_r != table->pending_w;
71 avr_is_interrupt_pending(
73 avr_int_vector_t * vector)
75 return vector->pending;
79 avr_is_interrupt_enabled(
81 avr_int_vector_t * vector)
83 return avr_regbit_get(avr, vector->enable);
89 avr_int_vector_t * vector)
91 if (!vector || !vector->vector)
94 printf("%s raising %d (enabled %d)\n", __FUNCTION__, vector->vector, avr_regbit_get(avr, vector->enable));
95 if (vector->pending) {
97 printf("%s trying to double raise %d (enabled %d)\n", __FUNCTION__, vector->vector, avr_regbit_get(avr, vector->enable));
100 // always mark the 'raised' flag to one, even if the interrupt is disabled
101 // this allow "polling" for the "raised" flag, like for non-interrupt
102 // driven UART and so so. These flags are often "write one to clear"
103 if (vector->raised.reg)
104 avr_regbit_set(avr, vector->raised);
106 avr_raise_irq(&vector->irq, 1);
108 // If the interrupt is enabled, attempt to wake the core
109 if (avr_regbit_get(avr, vector->enable)) {
110 // Mark the interrupt as pending
113 avr_int_table_p table = &avr->interrupts;
115 table->pending[table->pending_w++] = vector;
116 table->pending_w = INT_FIFO_MOD(table->pending_w);
118 if (!table->pending_wait)
119 table->pending_wait = 1; // latency on interrupts ??
120 if (avr->state == cpu_Sleeping) {
122 printf("Waking CPU due to interrupt\n");
123 avr->state = cpu_Running; // in case we were sleeping
126 // return 'raised' even if it was already pending
133 avr_int_vector_t * vector)
138 printf("%s cleared %d\n", __FUNCTION__, vector->vector);
140 avr_raise_irq(&vector->irq, 0);
141 if (vector->raised.reg && !vector->raise_sticky)
142 avr_regbit_clear(avr, vector->raised);
146 avr_clear_interrupt_if(
148 avr_int_vector_t * vector,
151 if (avr_regbit_get(avr, vector->raised)) {
152 avr_clear_interrupt(avr, vector);
155 avr_regbit_setto(avr, vector->raised, old);
160 avr_get_interrupt_irq(
164 avr_int_table_p table = &avr->interrupts;
165 for (int i = 0; i < table->vector_count; i++)
166 if (table->vector[i]->vector == v)
167 return &table->vector[i]->irq;
172 * check whether interrupts are pending. If so, check if the interrupt "latency" is reached,
173 * and if so triggers the handlers and jump to the vector.
176 avr_service_interrupts(
182 if (!avr_has_pending_interrupts(avr))
185 avr_int_table_p table = &avr->interrupts;
187 if (!table->pending_wait) {
188 table->pending_wait = 2; // for next one...
191 table->pending_wait--;
192 if (table->pending_wait)
195 // how many are pending...
196 int cnt = table->pending_w > table->pending_r ?
197 table->pending_w - table->pending_r :
198 (table->pending_w + INT_FIFO_SIZE) - table->pending_r;
199 // locate the highest priority one
202 for (int ii = 0; ii < cnt; ii++) {
203 int vi = INT_FIFO_MOD(table->pending_r + ii);
204 avr_int_vector_t * v = table->pending[vi];
205 if (v->vector < min) {
210 avr_int_vector_t * vector = table->pending[mini];
212 // now move the one at the front of the fifo in the slot of
213 // the one we service
214 table->pending[mini] = table->pending[table->pending_r++];
215 table->pending_r = INT_FIFO_MOD(table->pending_r);
217 // if that single interrupt is masked, ignore it and continue
218 // could also have been disabled, or cleared
219 if (!avr_regbit_get(avr, vector->enable) || !vector->pending) {
222 if (vector && vector->trace)
223 printf("%s calling %d\n", __FUNCTION__, (int)vector->vector);
224 _avr_push16(avr, avr->pc >> 1);
226 avr->pc = vector->vector * avr->vector_size;
228 avr_clear_interrupt(avr, vector);