target/avr: CPU class: Add interrupt handling support
[qemu/ar7.git] / target / avr / helper.c
blob7174e4858e69873baa7de771e0babf8bc3ca8d0e
1 /*
2 * QEMU AVR CPU helpers
4 * Copyright (c) 2016-2020 Michael Rolnik
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see
18 * <http://www.gnu.org/licenses/lgpl-2.1.html>
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/exec-all.h"
24 #include "exec/helper-proto.h"
26 bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
28 bool ret = false;
29 CPUClass *cc = CPU_GET_CLASS(cs);
30 AVRCPU *cpu = AVR_CPU(cs);
31 CPUAVRState *env = &cpu->env;
33 if (interrupt_request & CPU_INTERRUPT_RESET) {
34 if (cpu_interrupts_enabled(env)) {
35 cs->exception_index = EXCP_RESET;
36 cc->do_interrupt(cs);
38 cs->interrupt_request &= ~CPU_INTERRUPT_RESET;
40 ret = true;
43 if (interrupt_request & CPU_INTERRUPT_HARD) {
44 if (cpu_interrupts_enabled(env) && env->intsrc != 0) {
45 int index = ctz32(env->intsrc);
46 cs->exception_index = EXCP_INT(index);
47 cc->do_interrupt(cs);
49 env->intsrc &= env->intsrc - 1; /* clear the interrupt */
50 cs->interrupt_request &= ~CPU_INTERRUPT_HARD;
52 ret = true;
55 return ret;
58 void avr_cpu_do_interrupt(CPUState *cs)
60 AVRCPU *cpu = AVR_CPU(cs);
61 CPUAVRState *env = &cpu->env;
63 uint32_t ret = env->pc_w;
64 int vector = 0;
65 int size = avr_feature(env, AVR_FEATURE_JMP_CALL) ? 2 : 1;
66 int base = 0;
68 if (cs->exception_index == EXCP_RESET) {
69 vector = 0;
70 } else if (env->intsrc != 0) {
71 vector = ctz32(env->intsrc) + 1;
74 if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) {
75 cpu_stb_data(env, env->sp--, (ret & 0x0000ff));
76 cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8);
77 cpu_stb_data(env, env->sp--, (ret & 0xff0000) >> 16);
78 } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) {
79 cpu_stb_data(env, env->sp--, (ret & 0x0000ff));
80 cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8);
81 } else {
82 cpu_stb_data(env, env->sp--, (ret & 0x0000ff));
85 env->pc_w = base + vector * size;
86 env->sregI = 0; /* clear Global Interrupt Flag */
88 cs->exception_index = -1;