X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=simavr%2Fsim%2Fsim_interrupts.c;h=a2f3758709dad1f15c3844a1f5e5591942c13a23;hb=ead39534384a577ba325c9a95cb58691f15c4f6f;hp=e5d1609a3421c50cbb691b6f178c4789bc48a2f0;hpb=67688243000a1928b03f470f11fa3c353d229bd6;p=simavr diff --git a/simavr/sim/sim_interrupts.c b/simavr/sim/sim_interrupts.c index e5d1609..a2f3758 100644 --- a/simavr/sim/sim_interrupts.c +++ b/simavr/sim/sim_interrupts.c @@ -1,7 +1,7 @@ /* sim_interrupts.c - Copyright 2008, 2009 Michel Pollet + Copyright 2008-2012 Michel Pollet This file is part of simavr. @@ -25,41 +25,68 @@ #include #include #include "sim_interrupts.h" +#include "sim_avr.h" #include "sim_core.h" // modulo a cursor value on the pending interrupt fifo -#define INT_FIFO_SIZE (sizeof(avr->pending) / sizeof(avr_int_vector_t *)) +#define INT_FIFO_SIZE (sizeof(table->pending) / sizeof(avr_int_vector_t *)) #define INT_FIFO_MOD(_v) ((_v) & (INT_FIFO_SIZE - 1)) -void avr_register_vector(avr_t *avr, avr_int_vector_t * vector) +void +avr_interrupt_reset( + avr_t * avr ) { - if (vector->vector) { - vector->irq.irq = vector->vector; - avr->vector[avr->vector_count++] = vector; - if (vector->trace) - printf("%s register vector %d (enabled %04x:%d)\n", __FUNCTION__, vector->vector, vector->enable.reg, vector->enable.bit); + avr_int_table_p table = &avr->interrupts; + memset(table, 0, sizeof(*table)); +} - if (!vector->enable.reg) - printf("avr_register_vector: No 'enable' bit on vector %d !\n", vector->vector); - } +void +avr_register_vector( + avr_t *avr, + avr_int_vector_t * vector) +{ + if (!vector->vector) + return; + + avr_int_table_p table = &avr->interrupts; + + vector->irq.irq = vector->vector; + table->vector[table->vector_count++] = vector; + if (vector->trace) + printf("%s register vector %d (enabled %04x:%d)\n", __FUNCTION__, vector->vector, vector->enable.reg, vector->enable.bit); + + if (!vector->enable.reg) + AVR_LOG(avr, LOG_WARNING, "INT: avr_register_vector: No 'enable' bit on vector %d !\n", vector->vector); } -int avr_has_pending_interrupts(avr_t * avr) +int +avr_has_pending_interrupts( + avr_t * avr) { - return avr->pending_r != avr->pending_w; + avr_int_table_p table = &avr->interrupts; + return table->pending_r != table->pending_w; } -int avr_is_interrupt_pending(avr_t * avr, avr_int_vector_t * vector) +int +avr_is_interrupt_pending( + avr_t * avr, + avr_int_vector_t * vector) { return vector->pending; } -int avr_is_interrupt_enabled(avr_t * avr, avr_int_vector_t * vector) +int +avr_is_interrupt_enabled( + avr_t * avr, + avr_int_vector_t * vector) { return avr_regbit_get(avr, vector->enable); } -int avr_raise_interrupt(avr_t * avr, avr_int_vector_t * vector) +int +avr_raise_interrupt( + avr_t * avr, + avr_int_vector_t * vector) { if (!vector || !vector->vector) return 0; @@ -71,23 +98,26 @@ int avr_raise_interrupt(avr_t * avr, avr_int_vector_t * vector) return 0; } // always mark the 'raised' flag to one, even if the interrupt is disabled - // this allow "pooling" for the "raised" flag, like for non-interrupt + // this allow "polling" for the "raised" flag, like for non-interrupt // driven UART and so so. These flags are often "write one to clear" if (vector->raised.reg) avr_regbit_set(avr, vector->raised); - // Mark the interrupt as pending - vector->pending = 1; - avr->pending[avr->pending_w++] = vector; - avr->pending_w = INT_FIFO_MOD(avr->pending_w); - avr_raise_irq(&vector->irq, 1); // If the interrupt is enabled, attempt to wake the core if (avr_regbit_get(avr, vector->enable)) { - if (!avr->pending_wait) - avr->pending_wait = 1; // latency on interrupts ?? - if (avr->state != cpu_Running) { + // Mark the interrupt as pending + vector->pending = 1; + + avr_int_table_p table = &avr->interrupts; + + table->pending[table->pending_w++] = vector; + table->pending_w = INT_FIFO_MOD(table->pending_w); + + if (!table->pending_wait) + table->pending_wait = 1; // latency on interrupts ?? + if (avr->state == cpu_Sleeping) { if (vector->trace) printf("Waking CPU due to interrupt\n"); avr->state = cpu_Running; // in case we were sleeping @@ -97,7 +127,10 @@ int avr_raise_interrupt(avr_t * avr, avr_int_vector_t * vector) return 1; } -void avr_clear_interrupt(avr_t * avr, avr_int_vector_t * vector) +void +avr_clear_interrupt( + avr_t * avr, + avr_int_vector_t * vector) { if (!vector) return; @@ -105,26 +138,33 @@ void avr_clear_interrupt(avr_t * avr, avr_int_vector_t * vector) printf("%s cleared %d\n", __FUNCTION__, vector->vector); vector->pending = 0; avr_raise_irq(&vector->irq, 0); - if (vector->raised.reg) + if (vector->raised.reg && !vector->raise_sticky) avr_regbit_clear(avr, vector->raised); } -int avr_clear_interrupt_if(avr_t * avr, avr_int_vector_t * vector, uint8_t old) +int +avr_clear_interrupt_if( + avr_t * avr, + avr_int_vector_t * vector, + uint8_t old) { if (avr_regbit_get(avr, vector->raised)) { avr_clear_interrupt(avr, vector); - avr_regbit_clear(avr, vector->raised); return 1; } avr_regbit_setto(avr, vector->raised, old); return 0; } -avr_irq_t * avr_get_interrupt_irq(avr_t * avr, uint8_t v) +avr_irq_t * +avr_get_interrupt_irq( + avr_t * avr, + uint8_t v) { - for (int i = 0; i < avr->vector_count; i++) - if (avr->vector[i]->vector == v) - return &avr->vector[i]->irq; + avr_int_table_p table = &avr->interrupts; + for (int i = 0; i < table->vector_count; i++) + if (table->vector[i]->vector == v) + return &table->vector[i]->irq; return NULL; } @@ -132,7 +172,9 @@ avr_irq_t * avr_get_interrupt_irq(avr_t * avr, uint8_t v) * 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) +void +avr_service_interrupts( + avr_t * avr) { if (!avr->sreg[S_I]) return; @@ -140,35 +182,37 @@ void avr_service_interrupts(avr_t * avr) if (!avr_has_pending_interrupts(avr)) return; - if (!avr->pending_wait) { - avr->pending_wait = 2; // for next one... + avr_int_table_p table = &avr->interrupts; + + if (!table->pending_wait) { + table->pending_wait = 2; // for next one... return; } - avr->pending_wait--; - if (avr->pending_wait) + table->pending_wait--; + if (table->pending_wait) return; // how many are pending... - int cnt = avr->pending_w > avr->pending_r ? - avr->pending_w - avr->pending_r : - (avr->pending_w+INT_FIFO_SIZE) - avr->pending_r; + 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(avr->pending_r + ii); - avr_int_vector_t * v = avr->pending[vi]; + 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 = avr->pending[mini]; + 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 - avr->pending[mini] = avr->pending[avr->pending_r++]; - avr->pending_r = INT_FIFO_MOD(avr->pending_r); + 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