}
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;
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)
// 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
// 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
#endif
#include "sim_irq.h"
+#include "sim_interrupts.h"
#include "sim_cycle_timers.h"
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,
#include "sim_io.h"
#include "sim_regbit.h"
-#include "sim_interrupts.h"
-#include "sim_cycle_timers.h"
#endif /*__SIM_AVR_H__*/
#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
avr_cycle_count_t
avr_cycle_timer_process(
struct avr_t * avr);
+void
+avr_cycle_timer_reset(
+ struct avr_t * avr);
#ifdef __cplusplus
};
#include <string.h>
#include <strings.h>
#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
// 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");
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;
}
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
#ifndef __SIM_INTERRUPTS_H__
#define __SIM_INTERRUPTS_H__
-#include "sim_avr.h"
+#include "sim_avr_types.h"
#include "sim_irq.h"
#ifdef __cplusplus
// 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);
// 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
// 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