/* * check whether interrupts are pending. If so, check if the interrupt "latency" is reached, * and if so triggers the handlers and jump to the vector. */ void avr_service_interrupts( avr_t * avr) { if (!avr->sreg[S_I] || !avr->interrupt_state) return; if (avr->interrupt_state < 0) { avr->interrupt_state++; if (avr->interrupt_state == 0) avr->interrupt_state = avr_has_pending_interrupts(avr); return; } avr_int_table_p table = &avr->interrupts; // how many are pending... int cnt = avr_int_pending_get_read_size(&table->pending); // locate the highest priority one int min = 0xff; int mini = 0; for (int ii = 0; ii < cnt; ii++) { avr_int_vector_t * v = avr_int_pending_read_at(&table->pending, ii); if (v->vector < min) { min = v->vector; mini = ii; } } avr_int_vector_t * vector = avr_int_pending_read_at(&table->pending, mini); // now move the one at the front of the fifo in the slot of // the one we service table->pending.buffer[(table->pending.read + mini) % avr_int_pending_fifo_size] = avr_int_pending_read(&table->pending); avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); // if that single interrupt is masked, ignore it and continue // could also have been disabled, or cleared if (!avr_regbit_get(avr, vector->enable) || !vector->pending) { vector->pending = 0; avr->interrupt_state = avr_has_pending_interrupts(avr); } else { if (vector && vector->trace) printf("%s calling %d\n", __FUNCTION__, (int)vector->vector); _avr_push_addr(avr, avr->pc); avr_sreg_set(avr, S_I, 0); avr->pc = vector->vector * avr->vector_size; avr_raise_irq(vector->irq + AVR_INT_IRQ_RUNNING, 1); avr_raise_irq(table->irq + AVR_INT_IRQ_RUNNING, vector->vector); if (table->running_ptr == ARRAY_SIZE(table->running)) { AVR_LOG(avr, LOG_ERROR, "%s run out of nested stack!", __func__); } else { table->running[table->running_ptr++] = vector; } avr_clear_interrupt(avr, vector); } }
/* * check whether interrupts are pending. If so, check if the interrupt "latency" is reached, * and if so triggers the handlers and jump to the vector. */ void avr_service_interrupts( avr_t * avr) { if (!avr->sreg[S_I]) return; if (avr->interrupt_state) { if (avr->interrupt_state < 0) { avr->interrupt_state++; if (avr->interrupt_state == 0) avr->interrupt_state = avr_has_pending_interrupts(avr); return; } } else return; avr_int_table_p table = &avr->interrupts; // how many are pending... int cnt = table->pending_w > table->pending_r ? table->pending_w - table->pending_r : (table->pending_w + INT_FIFO_SIZE) - table->pending_r; // locate the highest priority one int min = 0xff; int mini = 0; for (int ii = 0; ii < cnt; ii++) { int vi = INT_FIFO_MOD(table->pending_r + ii); avr_int_vector_t * v = table->pending[vi]; if (v->vector < min) { min = v->vector; mini = vi; } } avr_int_vector_t * vector = table->pending[mini]; // now move the one at the front of the fifo in the slot of // the one we service table->pending[mini] = table->pending[table->pending_r++]; table->pending_r = INT_FIFO_MOD(table->pending_r); // if that single interrupt is masked, ignore it and continue // could also have been disabled, or cleared if (!avr_regbit_get(avr, vector->enable) || !vector->pending) { vector->pending = 0; avr->interrupt_state = avr_has_pending_interrupts(avr); } else { if (vector && vector->trace) printf("%s calling %d\n", __FUNCTION__, (int)vector->vector); _avr_push_addr(avr, avr->pc); avr_sreg_set(avr, S_I, 0); avr->pc = vector->vector * avr->vector_size; avr_clear_interrupt(avr, vector); } }
/* this is called uppon RETI. */ void avr_interrupt_reti( struct avr_t * avr) { avr_int_table_p table = &avr->interrupts; if (table->running_ptr) { avr_int_vector_t * vector = table->running[--table->running_ptr]; avr_raise_irq(vector->irq + AVR_INT_IRQ_RUNNING, 0); } avr_raise_irq(table->irq + AVR_INT_IRQ_RUNNING, table->running_ptr > 0 ? table->running[table->running_ptr-1]->vector : 0); avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); }
int avr_clear_interrupt_if( avr_t * avr, avr_int_vector_t * vector, uint8_t old) { avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); if (avr_regbit_get(avr, vector->raised)) { avr_clear_interrupt(avr, vector); return 1; } avr_regbit_setto(avr, vector->raised, old); return 0; }
void avr_clear_interrupt( avr_t * avr, avr_int_vector_t * vector) { if (!vector) return; if (vector->trace) printf("%s cleared %d\n", __FUNCTION__, vector->vector); vector->pending = 0; avr_raise_irq(vector->irq + AVR_INT_IRQ_PENDING, 0); avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); if (vector->raised.reg && !vector->raise_sticky) avr_regbit_clear(avr, vector->raised); }