From: Michel Pollet Date: Sat, 25 Feb 2012 17:57:59 +0000 (+0000) Subject: interrupts: Isolated runtime data X-Git-Tag: v1.0b1~42 X-Git-Url: https://git.htl-mechatronik.at/public/?a=commitdiff_plain;h=d4032ea9fae0c8a6fdd020f4f8fd448a044757a3;p=sx%2Fsimavr.git interrupts: Isolated runtime data Split the runtime data related to interrupts into it's own struct, and updated anyone using it directly. Ultimately it would be the goal not to have to pass an avr_t around to all the functions. Signed-off-by: Michel Pollet --- diff --git a/simavr/sim/run_avr.c b/simavr/sim/run_avr.c index e43424f..0c1fddd 100644 --- a/simavr/sim/run_avr.c +++ b/simavr/sim/run_avr.c @@ -153,8 +153,8 @@ int main(int argc, char *argv[]) } avr->trace = trace; for (int ti = 0; ti < trace_vectors_count; ti++) - if (avr->vector[trace_vectors[ti]]) - avr->vector[trace_vectors[ti]]->trace++; + if (avr->interrupts.vector[trace_vectors[ti]]) + avr->interrupts.vector[trace_vectors[ti]]->trace = 1; // even if not setup at startup, activate gdb if crashing avr->gdb_port = 1234; diff --git a/simavr/sim/sim_avr.c b/simavr/sim/sim_avr.c index 657131b..6cda116 100644 --- a/simavr/sim/sim_avr.c +++ b/simavr/sim/sim_avr.c @@ -82,7 +82,8 @@ void avr_reset(avr_t * avr) avr->sreg[i] = 0; if (avr->reset) avr->reset(avr); - + avr_interrupt_reset(avr); + avr_cycle_timer_reset(avr); avr_io_t * port = avr->io_port; while (port) { if (port->reset) @@ -201,7 +202,7 @@ void avr_callback_run_gdb(avr_t * avr) // if we just re-enabled the interrupts... // double buffer the I flag, to detect that edge if (avr->sreg[S_I] && !avr->i_shadow) - avr->pending_wait++; + avr->interrupts.pending_wait++; avr->i_shadow = avr->sreg[S_I]; // run the cycle timers, get the suggested sleep time @@ -255,7 +256,7 @@ void avr_callback_run_raw(avr_t * avr) // if we just re-enabled the interrupts... // double buffer the I flag, to detect that edge if (avr->sreg[S_I] && !avr->i_shadow) - avr->pending_wait++; + avr->interrupts.pending_wait++; avr->i_shadow = avr->sreg[S_I]; // run the cycle timers, get the suggested sleeo time diff --git a/simavr/sim/sim_avr.h b/simavr/sim/sim_avr.h index a91c2b9..6c0fc03 100644 --- a/simavr/sim/sim_avr.h +++ b/simavr/sim/sim_avr.h @@ -27,6 +27,7 @@ extern "C" { #endif #include "sim_irq.h" +#include "sim_interrupts.h" #include "sim_cycle_timers.h" struct avr_t; @@ -229,14 +230,10 @@ typedef struct avr_t { // queue of io modules struct avr_io_t *io_port; + // cycle timers tracking & delivery avr_cycle_timer_pool_t cycle_timers; - - // interrupt vectors, and their enable/clear registers - struct avr_int_vector_t * vector[64]; - uint8_t vector_count; - uint8_t pending_wait; // number of cycles to wait for pending - struct avr_int_vector_t * pending[64]; // needs to be >= vectors and a power of two - uint8_t pending_w, pending_r; // fifo cursors + // interrupt vectors and delivery fifo + avr_int_table_t interrupts; // DEBUG ONLY -- value ignored if CONFIG_SIMAVR_TRACE = 0 int trace : 1, @@ -354,8 +351,6 @@ void avr_callback_run_raw(avr_t * avr); #include "sim_io.h" #include "sim_regbit.h" -#include "sim_interrupts.h" -#include "sim_cycle_timers.h" #endif /*__SIM_AVR_H__*/ diff --git a/simavr/sim/sim_cycle_timers.c b/simavr/sim/sim_cycle_timers.c index bca155c..d11639c 100644 --- a/simavr/sim/sim_cycle_timers.c +++ b/simavr/sim/sim_cycle_timers.c @@ -26,6 +26,13 @@ #include "sim_time.h" #include "sim_cycle_timers.h" +void +avr_cycle_timer_reset( + struct avr_t * avr) +{ + avr_cycle_timer_pool_t * pool = &avr->cycle_timers; + memset(pool, 0, sizeof(*pool)); +} // no sanity checks checking here, on purpose static void diff --git a/simavr/sim/sim_cycle_timers.h b/simavr/sim/sim_cycle_timers.h index 7ec3f9e..9de7f40 100644 --- a/simavr/sim/sim_cycle_timers.h +++ b/simavr/sim/sim_cycle_timers.h @@ -92,6 +92,9 @@ avr_cycle_timer_status( avr_cycle_count_t avr_cycle_timer_process( struct avr_t * avr); +void +avr_cycle_timer_reset( + struct avr_t * avr); #ifdef __cplusplus }; diff --git a/simavr/sim/sim_interrupts.c b/simavr/sim/sim_interrupts.c index 689c904..3e094e5 100644 --- a/simavr/sim/sim_interrupts.c +++ b/simavr/sim/sim_interrupts.c @@ -25,33 +25,46 @@ #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_interrupt_reset( + avr_t * avr ) +{ + avr_int_table_p table = &avr->interrupts; + memset(table, 0, sizeof(*table)); +} + void avr_register_vector( avr_t *avr, avr_int_vector_t * vector) { - 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); + if (!vector->vector) + return; - if (!vector->enable.reg) - printf("avr_register_vector: No 'enable' bit on vector %d !\n", vector->vector); - } + 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) + printf("avr_register_vector: No 'enable' bit on vector %d !\n", vector->vector); } 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 @@ -92,15 +105,18 @@ avr_raise_interrupt( // Mark the interrupt as pending vector->pending = 1; - avr->pending[avr->pending_w++] = vector; - avr->pending_w = INT_FIFO_MOD(avr->pending_w); + + avr_int_table_p table = &avr->interrupts; + + table->pending[table->pending_w++] = vector; + table->pending_w = INT_FIFO_MOD(table->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 (!table->pending_wait) + table->pending_wait = 1; // latency on interrupts ?? if (avr->state != cpu_Running) { if (vector->trace) printf("Waking CPU due to interrupt\n"); @@ -146,9 +162,10 @@ 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; } @@ -166,35 +183,37 @@ avr_service_interrupts( 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 diff --git a/simavr/sim/sim_interrupts.h b/simavr/sim/sim_interrupts.h index e98659e..148b28c 100644 --- a/simavr/sim/sim_interrupts.h +++ b/simavr/sim/sim_interrupts.h @@ -22,7 +22,7 @@ #ifndef __SIM_INTERRUPTS_H__ #define __SIM_INTERRUPTS_H__ -#include "sim_avr.h" +#include "sim_avr_types.h" #include "sim_irq.h" #ifdef __cplusplus @@ -31,51 +31,62 @@ extern "C" { // interrupt vector for the IO modules typedef struct avr_int_vector_t { - uint8_t pending : 1, vector; // vector number, zero (reset) is reserved - avr_regbit_t enable; // IO register index for the "interrupt enable" flag for this vector - avr_regbit_t raised; // IO register index for the register where the "raised" flag is (optional) + uint8_t vector; // vector number, zero (reset) is reserved + avr_regbit_t enable; // IO register index for the "interrupt enable" flag for this vector + avr_regbit_t raised; // IO register index for the register where the "raised" flag is (optional) - avr_irq_t irq; // raised to 1 when queued, to zero when called - uint8_t trace; // only for debug of a vector + avr_irq_t irq; // raised to 1 when queued, to zero when called + uint8_t pending : 1, // 1 while scheduled in the fifo + trace : 1; // only for debug of a vector } avr_int_vector_t; +// interrupt vectors, and their enable/clear registers +typedef struct avr_int_table_t { + avr_int_vector_t * vector[64]; + uint8_t vector_count; + uint8_t pending_wait; // number of cycles to wait for pending + avr_int_vector_t * pending[64]; // needs to be >= vectors and a power of two + uint8_t pending_w, + pending_r; // fifo cursors +} avr_int_table_t, *avr_int_table_p; + /* * Interrupt Helper Functions */ // register an interrupt vector. It's only needed if you want to use the "r_raised" flags void avr_register_vector( - avr_t *avr, + struct avr_t *avr, avr_int_vector_t * vector); // raise an interrupt (if enabled). The interrupt is latched and will be called later // return non-zero if the interrupt was raised and is now pending int avr_raise_interrupt( - avr_t * avr, + struct avr_t * avr, avr_int_vector_t * vector); // return non-zero if the AVR core has any pending interrupts int avr_has_pending_interrupts( - avr_t * avr); + struct avr_t * avr); // return nonzero if a specific interrupt vector is pending int avr_is_interrupt_pending( - avr_t * avr, + struct avr_t * avr, avr_int_vector_t * vector); // clear the "pending" status of an interrupt void avr_clear_interrupt( - avr_t * avr, + struct avr_t * avr, avr_int_vector_t * vector); // called by the core at each cycle to check whether an interrupt is pending void avr_service_interrupts( - avr_t * avr); + struct avr_t * avr); // clear the interrupt (inc pending) if "raised" flag is 1 int avr_clear_interrupt_if( - avr_t * avr, + struct avr_t * avr, avr_int_vector_t * vector, uint8_t old); @@ -83,9 +94,14 @@ avr_clear_interrupt_if( // this allows tracing of pending interrupts avr_irq_t * avr_get_interrupt_irq( - avr_t * avr, + struct avr_t * avr, uint8_t v); +// reset the interrupt table and the fifo +void +avr_interrupt_reset( + struct avr_t * avr ); + #ifdef __cplusplus }; #endif diff --git a/tests/tests.c b/tests/tests.c index c21b1ac..f389f4d 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -60,7 +60,7 @@ static int my_avr_run(avr_t * avr) // if we just re-enabled the interrupts... // double buffer the I flag, to detect that edge if (avr->sreg[S_I] && !avr->i_shadow) - avr->pending_wait++; + avr->interrupts.pending_wait++; avr->i_shadow = avr->sreg[S_I]; // run the cycle timers, get the suggested sleep time