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 printf("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 "pooling" 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)
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);
153 avr_regbit_clear(avr, vector->raised);
156 avr_regbit_setto(avr, vector->raised, old);
161 avr_get_interrupt_irq(
165 avr_int_table_p table = &avr->interrupts;
166 for (int i = 0; i < table->vector_count; i++)
167 if (table->vector[i]->vector == v)
168 return &table->vector[i]->irq;
173 * check whether interrupts are pending. If so, check if the interrupt "latency" is reached,
174 * and if so triggers the handlers and jump to the vector.
177 avr_service_interrupts(
183 if (!avr_has_pending_interrupts(avr))
186 avr_int_table_p table = &avr->interrupts;
188 if (!table->pending_wait) {
189 table->pending_wait = 2; // for next one...
192 table->pending_wait--;
193 if (table->pending_wait)
196 // how many are pending...
197 int cnt = table->pending_w > table->pending_r ?
198 table->pending_w - table->pending_r :
199 (table->pending_w + INT_FIFO_SIZE) - table->pending_r;
200 // locate the highest priority one
203 for (int ii = 0; ii < cnt; ii++) {
204 int vi = INT_FIFO_MOD(table->pending_r + ii);
205 avr_int_vector_t * v = table->pending[vi];
206 if (v->vector < min) {
211 avr_int_vector_t * vector = table->pending[mini];
213 // now move the one at the front of the fifo in the slot of
214 // the one we service
215 table->pending[mini] = table->pending[table->pending_r++];
216 table->pending_r = INT_FIFO_MOD(table->pending_r);
218 // if that single interrupt is masked, ignore it and continue
219 // could also have been disabled, or cleared
220 if (!avr_regbit_get(avr, vector->enable) || !vector->pending) {
223 if (vector && vector->trace)
224 printf("%s calling %d\n", __FUNCTION__, (int)vector->vector);
225 _avr_push16(avr, avr->pc >> 1);
227 avr->pc = vector->vector * avr->vector_size;
229 avr_clear_interrupt(avr, vector);