]>
Commit | Line | Data |
---|---|---|
075d047e YS |
1 | /* |
2 | * RX emulation | |
3 | * | |
4 | * Copyright (c) 2019 Yoshinori Sato | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms and conditions of the GNU General Public License, | |
8 | * version 2 or later, as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope it will be useful, but WITHOUT | |
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | * more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License along with | |
16 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #include "qemu/osdep.h" | |
20 | #include "qemu/bitops.h" | |
21 | #include "cpu.h" | |
22 | #include "exec/log.h" | |
23 | #include "exec/cpu_ldst.h" | |
075d047e YS |
24 | #include "hw/irq.h" |
25 | ||
26 | void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte) | |
27 | { | |
28 | if (env->psw_pm == 0) { | |
29 | env->psw_ipl = FIELD_EX32(psw, PSW, IPL); | |
30 | if (rte) { | |
31 | /* PSW.PM can write RTE and RTFI */ | |
32 | env->psw_pm = FIELD_EX32(psw, PSW, PM); | |
33 | } | |
34 | env->psw_u = FIELD_EX32(psw, PSW, U); | |
35 | env->psw_i = FIELD_EX32(psw, PSW, I); | |
36 | } | |
37 | env->psw_o = FIELD_EX32(psw, PSW, O) << 31; | |
38 | env->psw_s = FIELD_EX32(psw, PSW, S) << 31; | |
39 | env->psw_z = 1 - FIELD_EX32(psw, PSW, Z); | |
40 | env->psw_c = FIELD_EX32(psw, PSW, C); | |
41 | } | |
42 | ||
65c575b6 PMD |
43 | #ifndef CONFIG_USER_ONLY |
44 | ||
075d047e YS |
45 | #define INT_FLAGS (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR) |
46 | void rx_cpu_do_interrupt(CPUState *cs) | |
47 | { | |
38688fdb | 48 | RXCPU *cpu = RX_CPU(cs); |
075d047e YS |
49 | CPURXState *env = &cpu->env; |
50 | int do_irq = cs->interrupt_request & INT_FLAGS; | |
51 | uint32_t save_psw; | |
52 | ||
53 | env->in_sleep = 0; | |
54 | ||
55 | if (env->psw_u) { | |
56 | env->usp = env->regs[0]; | |
57 | } else { | |
58 | env->isp = env->regs[0]; | |
59 | } | |
60 | save_psw = rx_cpu_pack_psw(env); | |
61 | env->psw_pm = env->psw_i = env->psw_u = 0; | |
62 | ||
63 | if (do_irq) { | |
64 | if (do_irq & CPU_INTERRUPT_FIR) { | |
65 | env->bpc = env->pc; | |
66 | env->bpsw = save_psw; | |
67 | env->pc = env->fintv; | |
68 | env->psw_ipl = 15; | |
69 | cs->interrupt_request &= ~CPU_INTERRUPT_FIR; | |
70 | qemu_set_irq(env->ack, env->ack_irq); | |
71 | qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n"); | |
72 | } else if (do_irq & CPU_INTERRUPT_HARD) { | |
73 | env->isp -= 4; | |
74 | cpu_stl_data(env, env->isp, save_psw); | |
75 | env->isp -= 4; | |
76 | cpu_stl_data(env, env->isp, env->pc); | |
77 | env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4); | |
78 | env->psw_ipl = env->ack_ipl; | |
79 | cs->interrupt_request &= ~CPU_INTERRUPT_HARD; | |
80 | qemu_set_irq(env->ack, env->ack_irq); | |
81 | qemu_log_mask(CPU_LOG_INT, | |
82 | "interrupt 0x%02x raised\n", env->ack_irq); | |
83 | } | |
84 | } else { | |
85 | uint32_t vec = cs->exception_index; | |
86 | const char *expname = "unknown exception"; | |
87 | ||
88 | env->isp -= 4; | |
89 | cpu_stl_data(env, env->isp, save_psw); | |
90 | env->isp -= 4; | |
91 | cpu_stl_data(env, env->isp, env->pc); | |
92 | ||
93 | if (vec < 0x100) { | |
94 | env->pc = cpu_ldl_data(env, 0xffffffc0 + vec * 4); | |
95 | } else { | |
96 | env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4); | |
97 | } | |
98 | switch (vec) { | |
99 | case 20: | |
100 | expname = "privilege violation"; | |
101 | break; | |
102 | case 21: | |
103 | expname = "access exception"; | |
104 | break; | |
105 | case 23: | |
106 | expname = "illegal instruction"; | |
107 | break; | |
108 | case 25: | |
109 | expname = "fpu exception"; | |
110 | break; | |
111 | case 30: | |
112 | expname = "non-maskable interrupt"; | |
113 | break; | |
114 | case 0x100 ... 0x1ff: | |
115 | expname = "unconditional trap"; | |
116 | } | |
117 | qemu_log_mask(CPU_LOG_INT, "exception 0x%02x [%s] raised\n", | |
118 | (vec & 0xff), expname); | |
119 | } | |
120 | env->regs[0] = env->isp; | |
121 | } | |
122 | ||
123 | bool rx_cpu_exec_interrupt(CPUState *cs, int interrupt_request) | |
124 | { | |
38688fdb | 125 | RXCPU *cpu = RX_CPU(cs); |
075d047e YS |
126 | CPURXState *env = &cpu->env; |
127 | int accept = 0; | |
128 | /* hardware interrupt (Normal) */ | |
129 | if ((interrupt_request & CPU_INTERRUPT_HARD) && | |
130 | env->psw_i && (env->psw_ipl < env->req_ipl)) { | |
131 | env->ack_irq = env->req_irq; | |
132 | env->ack_ipl = env->req_ipl; | |
133 | accept = 1; | |
134 | } | |
135 | /* hardware interrupt (FIR) */ | |
136 | if ((interrupt_request & CPU_INTERRUPT_FIR) && | |
137 | env->psw_i && (env->psw_ipl < 15)) { | |
138 | accept = 1; | |
139 | } | |
140 | if (accept) { | |
141 | rx_cpu_do_interrupt(cs); | |
142 | return true; | |
143 | } | |
144 | return false; | |
145 | } | |
146 | ||
147 | hwaddr rx_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | |
148 | { | |
149 | return addr; | |
150 | } | |
6d2d454a PMD |
151 | |
152 | #endif /* !CONFIG_USER_ONLY */ |