}
avr_raise_irq(vector->irq + AVR_INT_IRQ_PENDING, 1);
- avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, 1);
+ avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, vector->vector);
// If the interrupt is enabled, attempt to wake the core
if (avr_regbit_get(avr, vector->enable)) {
avr_has_pending_interrupts(avr) ?
avr_int_pending_read_at(
&avr->interrupts.pending, 0)->vector : 0,
- !avr_has_pending_interrupts(avr));
+ avr_has_pending_interrupts(avr));
if (vector->raised.reg && !vector->raise_sticky)
avr_regbit_clear(avr, vector->raised);
return NULL;
}
-/* this is called uppon RETI. */
+/* this is called upon RETI. */
void
avr_interrupt_reti(
struct avr_t * avr)
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));
}
/*
// destination for the swap.
table->pending.buffer[(table->pending.read + mini - 1) % avr_int_pending_fifo_size] = fifo_front;
}
- 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
--- /dev/null
+/*
+ attiny44_interrupt_irq_test.c
+
+ Copyright 2022 Giles Atkinson
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <avr/io.h>
+#include <stdio.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+#include <util/delay.h>
+#include <avr/cpufunc.h>
+#include "avr_mcu_section.h"
+
+AVR_MCU(F_CPU, "attiny44");
+AVR_MCU_VOLTAGES(5000, 5000, 3000) // VCC, AVCC, VREF - millivolts.
+
+static volatile int nest;
+
+ISR(INT0_vect)
+{
+ GPIOR1 = 1; // Signal to test harness
+ if (nest)
+ sei();
+}
+
+ISR(PCINT1_vect)
+{
+ GPIOR1 = 2;
+ if (nest)
+ sei();
+}
+
+ISR(ADC_vect)
+{
+ GPIOR1 = 3;
+ if (nest)
+ sei();
+}
+
+void go(void)
+{
+
+ /* Turn on the ADC. */
+
+ ADCSRA = _BV(ADEN) + _BV(ADSC) + _BV(ADIE); // Enable, start, clk scale = 2
+
+ /* Wait for ADC. */
+
+ while ((ADCSRA & (1 << ADIF)) == 0)
+ ;
+
+ sei(); // Three interrupts.
+
+ /* Wait for ADC interrupt. */
+
+ while (ADCSRA & _BV(ADIF))
+ ;
+ cli();
+}
+
+int main(void)
+{
+ /* Cause "external" and pin-change interrupts. */
+
+ GIMSK = _BV(INT0) + _BV(PCIE1); // Enable INTO and PORTB pin change.
+ MCUCR = 1; // Interrupt on either edge of PB2.
+ PCMSK1 = _BV(PCINT10); // Pin change interrupt for PB2.
+ PORTB = _BV(2); // Two interrupts if pull-ups configured.
+ DDRB = _BV(2); // Make sure of it.
+
+ go();
+
+ /* Do it again with interrupt nesting. */
+
+ nest = 1;
+ PORTB = 0; // Two interrupts.
+ go();
+
+ /* Final check: writing to GPIOR1 should have had not effect as the
+ * handler did not writr thr passed value.
+ */
+
+ if (GPIOR1)
+ GPIOR1 = 0xff;
+
+ /* Stop test by sleeping with interrupts off. */
+
+ sleep_cpu();
+}
--- /dev/null
+/*
+ test_attiny44_interrupt_irq_test.c
+
+ Copyright 2022 Giles Atkinson
+
+ This file is part of simavr.
+
+ simavr is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ simavr is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with simavr. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "sim_irq.h"
+#include "sim_interrupts.h"
+#include "tests.h"
+
+/* Accumulate log of events for comparison at the end. */
+
+static char log[512];
+static char *fill = log;
+
+#define LOG(...) \
+ (fill += snprintf(fill, (log + sizeof log) - fill, __VA_ARGS__))
+
+#define GPIOR1 ((avr_io_addr_t)0x34) // Unused I/O register.
+
+/* Callbacks for interrupt events. */
+
+static void any_pending(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+ LOG("P-%d%s ", value, irq->flags & IRQ_FLAG_FLOATING ? "f": "");
+}
+
+static void any_running(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+ LOG("R-%d ", value);
+}
+
+static void ext_pending(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+ LOG("PX-%d ", value);
+}
+
+static void ext_running(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+ LOG("RX-%d ", value);
+}
+
+static void pc1_pending(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+ LOG("PC-%d ", value);
+}
+
+static void pc1_running(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+ LOG("RC-%d ", value);
+}
+
+static void adc_pending(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+ LOG("PA-%d ", value);
+}
+
+static void adc_running(struct avr_irq_t *irq, uint32_t value, void *param)
+{
+ LOG("RA-%d ", value);
+}
+
+static void gpior1_change(struct avr_t *avr, avr_io_addr_t addr,
+ uint8_t v, void *param)
+{
+ LOG("*-%d ", v);
+}
+
+static const char *expected =
+ "PX-1 P-1 PC-1 P-3 PA-1 P-13 " // Raise three interrupts.
+ "RX-1 R-1 PX-0 P-3f *-1 RX-0 R-0 " // External (INT0) interrupt runs.
+ "RC-1 R-3 PC-0 P-13f *-2 RC-0 R-0 " // Pin change interrupt runs.
+ "RA-1 R-13 PA-0 P-0 *-3 RA-0 R-0 " // ADC interrupt runs.
+ "PX-1 P-1 PC-1 P-3 PA-1 P-13 " // Second round: raise three.
+ "RX-1 R-1 PX-0 P-3f *-1 " // External (INT0) interrupt runs.
+ "RC-1 R-3 PC-0 P-13f *-2 " // Pin change interrupt runs.
+ "RA-1 R-13 PA-0 P-0 *-3 RA-0 " // ADC interrupt runs.
+ "R-3 RC-0 R-1 RX-0 R-0 "; // Unwind stack.
+
+int main(int argc, char **argv) {
+ avr_t *avr;
+ avr_irq_t *irq;
+
+ tests_init(argc, argv);
+ avr = tests_init_avr("attiny44_interrupt_irq_test.axf");
+
+ /* Request callbacks on events in the interrupt code.. */
+
+ irq = avr_get_interrupt_irq(avr, AVR_INT_ANY);
+ avr_irq_register_notify(irq + AVR_INT_IRQ_PENDING, any_pending, NULL);
+ avr_irq_register_notify(irq + AVR_INT_IRQ_RUNNING, any_running, NULL);
+ irq = avr_get_interrupt_irq(avr, 1); // INT0 - pin PB2
+ avr_irq_register_notify(irq + AVR_INT_IRQ_PENDING, ext_pending, NULL);
+ avr_irq_register_notify(irq + AVR_INT_IRQ_RUNNING, ext_running, NULL);
+ irq = avr_get_interrupt_irq(avr, 3); // PCINT1 - Port B
+ avr_irq_register_notify(irq + AVR_INT_IRQ_PENDING, pc1_pending, NULL);
+ avr_irq_register_notify(irq + AVR_INT_IRQ_RUNNING, pc1_running, NULL);
+ irq = avr_get_interrupt_irq(avr, 13); // ADC
+ avr_irq_register_notify(irq + AVR_INT_IRQ_PENDING, adc_pending, NULL);
+ avr_irq_register_notify(irq + AVR_INT_IRQ_RUNNING, adc_running, NULL);
+
+ /* Watch GPIOR1 for interrupt handler activity. */
+
+ avr_register_io_write(avr, GPIOR1, gpior1_change, NULL);
+
+ /* Run program and check results. */
+
+ if (tests_run_test(avr, 100000) == LJR_CYCLE_TIMER)
+ fail("Timed out\n");
+ if (strcmp(expected, log))
+ fail("\nInternal log: %s.\n Expected: %s.\n", log, expected);
+ tests_success();
+ return 0;
+}