]>
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" | |
24 | #include "sysemu/sysemu.h" | |
25 | #include "hw/irq.h" | |
26 | ||
27 | void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte) | |
28 | { | |
29 | if (env->psw_pm == 0) { | |
30 | env->psw_ipl = FIELD_EX32(psw, PSW, IPL); | |
31 | if (rte) { | |
32 | /* PSW.PM can write RTE and RTFI */ | |
33 | env->psw_pm = FIELD_EX32(psw, PSW, PM); | |
34 | } | |
35 | env->psw_u = FIELD_EX32(psw, PSW, U); | |
36 | env->psw_i = FIELD_EX32(psw, PSW, I); | |
37 | } | |
38 | env->psw_o = FIELD_EX32(psw, PSW, O) << 31; | |
39 | env->psw_s = FIELD_EX32(psw, PSW, S) << 31; | |
40 | env->psw_z = 1 - FIELD_EX32(psw, PSW, Z); | |
41 | env->psw_c = FIELD_EX32(psw, PSW, C); | |
42 | } | |
43 | ||
44 | #define INT_FLAGS (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR) | |
45 | void rx_cpu_do_interrupt(CPUState *cs) | |
46 | { | |
38688fdb | 47 | RXCPU *cpu = RX_CPU(cs); |
075d047e YS |
48 | CPURXState *env = &cpu->env; |
49 | int do_irq = cs->interrupt_request & INT_FLAGS; | |
50 | uint32_t save_psw; | |
51 | ||
52 | env->in_sleep = 0; | |
53 | ||
54 | if (env->psw_u) { | |
55 | env->usp = env->regs[0]; | |
56 | } else { | |
57 | env->isp = env->regs[0]; | |
58 | } | |
59 | save_psw = rx_cpu_pack_psw(env); | |
60 | env->psw_pm = env->psw_i = env->psw_u = 0; | |
61 | ||
62 | if (do_irq) { | |
63 | if (do_irq & CPU_INTERRUPT_FIR) { | |
64 | env->bpc = env->pc; | |
65 | env->bpsw = save_psw; | |
66 | env->pc = env->fintv; | |
67 | env->psw_ipl = 15; | |
68 | cs->interrupt_request &= ~CPU_INTERRUPT_FIR; | |
69 | qemu_set_irq(env->ack, env->ack_irq); | |
70 | qemu_log_mask(CPU_LOG_INT, "fast interrupt raised\n"); | |
71 | } else if (do_irq & CPU_INTERRUPT_HARD) { | |
72 | env->isp -= 4; | |
73 | cpu_stl_data(env, env->isp, save_psw); | |
74 | env->isp -= 4; | |
75 | cpu_stl_data(env, env->isp, env->pc); | |
76 | env->pc = cpu_ldl_data(env, env->intb + env->ack_irq * 4); | |
77 | env->psw_ipl = env->ack_ipl; | |
78 | cs->interrupt_request &= ~CPU_INTERRUPT_HARD; | |
79 | qemu_set_irq(env->ack, env->ack_irq); | |
80 | qemu_log_mask(CPU_LOG_INT, | |
81 | "interrupt 0x%02x raised\n", env->ack_irq); | |
82 | } | |
83 | } else { | |
84 | uint32_t vec = cs->exception_index; | |
85 | const char *expname = "unknown exception"; | |
86 | ||
87 | env->isp -= 4; | |
88 | cpu_stl_data(env, env->isp, save_psw); | |
89 | env->isp -= 4; | |
90 | cpu_stl_data(env, env->isp, env->pc); | |
91 | ||
92 | if (vec < 0x100) { | |
93 | env->pc = cpu_ldl_data(env, 0xffffffc0 + vec * 4); | |
94 | } else { | |
95 | env->pc = cpu_ldl_data(env, env->intb + (vec & 0xff) * 4); | |
96 | } | |
97 | switch (vec) { | |
98 | case 20: | |
99 | expname = "privilege violation"; | |
100 | break; | |
101 | case 21: | |
102 | expname = "access exception"; | |
103 | break; | |
104 | case 23: | |
105 | expname = "illegal instruction"; | |
106 | break; | |
107 | case 25: | |
108 | expname = "fpu exception"; | |
109 | break; | |
110 | case 30: | |
111 | expname = "non-maskable interrupt"; | |
112 | break; | |
113 | case 0x100 ... 0x1ff: | |
114 | expname = "unconditional trap"; | |
115 | } | |
116 | qemu_log_mask(CPU_LOG_INT, "exception 0x%02x [%s] raised\n", | |
117 | (vec & 0xff), expname); | |
118 | } | |
119 | env->regs[0] = env->isp; | |
120 | } | |
121 | ||
122 | bool rx_cpu_exec_interrupt(CPUState *cs, int interrupt_request) | |
123 | { | |
38688fdb | 124 | RXCPU *cpu = RX_CPU(cs); |
075d047e YS |
125 | CPURXState *env = &cpu->env; |
126 | int accept = 0; | |
127 | /* hardware interrupt (Normal) */ | |
128 | if ((interrupt_request & CPU_INTERRUPT_HARD) && | |
129 | env->psw_i && (env->psw_ipl < env->req_ipl)) { | |
130 | env->ack_irq = env->req_irq; | |
131 | env->ack_ipl = env->req_ipl; | |
132 | accept = 1; | |
133 | } | |
134 | /* hardware interrupt (FIR) */ | |
135 | if ((interrupt_request & CPU_INTERRUPT_FIR) && | |
136 | env->psw_i && (env->psw_ipl < 15)) { | |
137 | accept = 1; | |
138 | } | |
139 | if (accept) { | |
140 | rx_cpu_do_interrupt(cs); | |
141 | return true; | |
142 | } | |
143 | return false; | |
144 | } | |
145 | ||
146 | hwaddr rx_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) | |
147 | { | |
148 | return addr; | |
149 | } |