]>
Commit | Line | Data |
---|---|---|
61766fe9 RH |
1 | /* |
2 | * QEMU HPPA CPU | |
3 | * | |
4 | * Copyright (c) 2016 Richard Henderson <rth@twiddle.net> | |
5 | * | |
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. | |
10 | * | |
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. | |
15 | * | |
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> | |
19 | */ | |
20 | ||
21 | #include "qemu/osdep.h" | |
22 | #include "qapi/error.h" | |
0442428a | 23 | #include "qemu/qemu-print.h" |
b8012ecf | 24 | #include "qemu/timer.h" |
61766fe9 | 25 | #include "cpu.h" |
0b8fa32f | 26 | #include "qemu/module.h" |
61766fe9 | 27 | #include "exec/exec-all.h" |
24f91e81 | 28 | #include "fpu/softfloat.h" |
2554f80f | 29 | #include "tcg/tcg.h" |
61766fe9 RH |
30 | |
31 | static void hppa_cpu_set_pc(CPUState *cs, vaddr value) | |
32 | { | |
33 | HPPACPU *cpu = HPPA_CPU(cs); | |
34 | ||
3c13b0ff RH |
35 | #ifdef CONFIG_USER_ONLY |
36 | value |= PRIV_USER; | |
37 | #endif | |
61766fe9 RH |
38 | cpu->env.iaoq_f = value; |
39 | cpu->env.iaoq_b = value + 4; | |
40 | } | |
41 | ||
e4fdf9df RH |
42 | static vaddr hppa_cpu_get_pc(CPUState *cs) |
43 | { | |
19da5d12 | 44 | CPUHPPAState *env = cpu_env(cs); |
e4fdf9df | 45 | |
19da5d12 RH |
46 | return hppa_form_gva_psw(env->psw, (env->psw & PSW_C ? env->iasq_f : 0), |
47 | env->iaoq_f & -4); | |
e4fdf9df RH |
48 | } |
49 | ||
b61603bf | 50 | void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, |
9dfcd243 | 51 | uint64_t *pcsbase, uint32_t *pflags) |
b61603bf | 52 | { |
d27fe7c3 | 53 | uint32_t flags = 0; |
9dfcd243 RH |
54 | uint64_t cs_base = 0; |
55 | ||
56 | /* | |
57 | * TB lookup assumes that PC contains the complete virtual address. | |
58 | * If we leave space+offset separate, we'll get ITLB misses to an | |
59 | * incomplete virtual address. This also means that we must separate | |
60 | * out current cpu privilege from the low bits of IAOQ_F. | |
61 | */ | |
62 | *pc = hppa_cpu_get_pc(env_cpu(env)); | |
63 | flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT; | |
64 | ||
9dfcd243 RH |
65 | /* |
66 | * The only really interesting case is if IAQ_Back is on the same page | |
67 | * as IAQ_Front, so that we can use goto_tb between the blocks. In all | |
68 | * other cases, we'll be ending the TranslationBlock with one insn and | |
69 | * not linking between them. | |
70 | */ | |
71 | if (env->iasq_f != env->iasq_b) { | |
72 | cs_base |= CS_BASE_DIFFSPACE; | |
73 | } else if ((env->iaoq_f ^ env->iaoq_b) & TARGET_PAGE_MASK) { | |
74 | cs_base |= CS_BASE_DIFFPAGE; | |
75 | } else { | |
76 | cs_base |= env->iaoq_b & ~TARGET_PAGE_MASK; | |
77 | } | |
b61603bf | 78 | |
d27fe7c3 RH |
79 | /* ??? E, T, H, L bits need to be here, when implemented. */ |
80 | flags |= env->psw_n * PSW_N; | |
81 | flags |= env->psw_xb; | |
82 | flags |= env->psw & (PSW_W | PSW_C | PSW_D | PSW_P); | |
83 | ||
b61603bf | 84 | #ifdef CONFIG_USER_ONLY |
b61603bf RH |
85 | flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; |
86 | #else | |
b61603bf RH |
87 | if ((env->sr[4] == env->sr[5]) |
88 | & (env->sr[4] == env->sr[6]) | |
89 | & (env->sr[4] == env->sr[7])) { | |
90 | flags |= TB_FLAG_SR_SAME; | |
91 | } | |
92 | #endif | |
93 | ||
9dfcd243 | 94 | *pcsbase = cs_base; |
b61603bf RH |
95 | *pflags = flags; |
96 | } | |
97 | ||
04a37d4c RH |
98 | static void hppa_cpu_synchronize_from_tb(CPUState *cs, |
99 | const TranslationBlock *tb) | |
61766fe9 RH |
100 | { |
101 | HPPACPU *cpu = HPPA_CPU(cs); | |
102 | ||
9dfcd243 | 103 | /* IAQ is always up-to-date before goto_tb. */ |
3d68ee7b | 104 | cpu->env.psw_n = (tb->flags & PSW_N) != 0; |
d27fe7c3 | 105 | cpu->env.psw_xb = tb->flags & (PSW_X | PSW_B); |
61766fe9 RH |
106 | } |
107 | ||
e9cc3aca RH |
108 | static void hppa_restore_state_to_opc(CPUState *cs, |
109 | const TranslationBlock *tb, | |
110 | const uint64_t *data) | |
111 | { | |
6dd9b145 | 112 | CPUHPPAState *env = cpu_env(cs); |
e9cc3aca | 113 | |
6dd9b145 RH |
114 | env->iaoq_f = (env->iaoq_f & TARGET_PAGE_MASK) | data[0]; |
115 | if (data[1] != INT32_MIN) { | |
116 | env->iaoq_b = env->iaoq_f + data[1]; | |
e9cc3aca | 117 | } |
6dd9b145 | 118 | env->unwind_breg = data[2]; |
e9cc3aca RH |
119 | /* |
120 | * Since we were executing the instruction at IAOQ_F, and took some | |
121 | * sort of action that provoked the cpu_restore_state, we can infer | |
122 | * that the instruction was not nullified. | |
123 | */ | |
6dd9b145 | 124 | env->psw_n = 0; |
e9cc3aca RH |
125 | } |
126 | ||
4f5f2548 RH |
127 | static bool hppa_cpu_has_work(CPUState *cs) |
128 | { | |
4a4554c6 | 129 | return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI); |
4f5f2548 RH |
130 | } |
131 | ||
a120d320 | 132 | static int hppa_cpu_mmu_index(CPUState *cs, bool ifetch) |
8f39cb77 RH |
133 | { |
134 | CPUHPPAState *env = cpu_env(cs); | |
135 | ||
136 | if (env->psw & (ifetch ? PSW_C : PSW_D)) { | |
137 | return PRIV_P_TO_MMU_IDX(env->iaoq_f & 3, env->psw & PSW_P); | |
138 | } | |
139 | /* mmu disabled */ | |
140 | return env->psw & PSW_W ? MMU_ABS_W_IDX : MMU_ABS_IDX; | |
141 | } | |
142 | ||
61766fe9 RH |
143 | static void hppa_cpu_disas_set_info(CPUState *cs, disassemble_info *info) |
144 | { | |
145 | info->mach = bfd_mach_hppa20; | |
146 | info->print_insn = print_insn_hppa; | |
147 | } | |
148 | ||
8535dd70 | 149 | #ifndef CONFIG_USER_ONLY |
8905770b MAL |
150 | static G_NORETURN |
151 | void hppa_cpu_do_unaligned_access(CPUState *cs, vaddr addr, | |
152 | MMUAccessType access_type, int mmu_idx, | |
153 | uintptr_t retaddr) | |
08aec8b5 RH |
154 | { |
155 | HPPACPU *cpu = HPPA_CPU(cs); | |
156 | CPUHPPAState *env = &cpu->env; | |
157 | ||
158 | cs->exception_index = EXCP_UNALIGN; | |
5ccd5017 | 159 | cpu_restore_state(cs, retaddr); |
910ada02 | 160 | hppa_set_ior_and_isr(env, addr, MMU_IDX_MMU_DISABLED(mmu_idx)); |
08aec8b5 | 161 | |
5ccd5017 | 162 | cpu_loop_exit(cs); |
08aec8b5 | 163 | } |
8535dd70 | 164 | #endif /* CONFIG_USER_ONLY */ |
08aec8b5 | 165 | |
61766fe9 RH |
166 | static void hppa_cpu_realizefn(DeviceState *dev, Error **errp) |
167 | { | |
168 | CPUState *cs = CPU(dev); | |
169 | HPPACPUClass *acc = HPPA_CPU_GET_CLASS(dev); | |
170 | Error *local_err = NULL; | |
171 | ||
172 | cpu_exec_realizefn(cs, &local_err); | |
173 | if (local_err != NULL) { | |
174 | error_propagate(errp, local_err); | |
175 | return; | |
176 | } | |
177 | ||
178 | qemu_init_vcpu(cs); | |
179 | acc->parent_realize(dev, errp); | |
49c29d6c RH |
180 | |
181 | #ifndef CONFIG_USER_ONLY | |
182 | { | |
183 | HPPACPU *cpu = HPPA_CPU(cs); | |
d7553f35 | 184 | |
49c29d6c RH |
185 | cpu->alarm_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, |
186 | hppa_cpu_alarm_timer, cpu); | |
d7553f35 | 187 | hppa_ptlbe(&cpu->env); |
49c29d6c RH |
188 | } |
189 | #endif | |
6dd9b145 RH |
190 | |
191 | /* Use pc-relative instructions always to simplify the translator. */ | |
192 | tcg_cflags_set(cs, CF_PCREL); | |
61766fe9 RH |
193 | } |
194 | ||
61766fe9 RH |
195 | static void hppa_cpu_initfn(Object *obj) |
196 | { | |
197 | CPUState *cs = CPU(obj); | |
198 | HPPACPU *cpu = HPPA_CPU(obj); | |
199 | CPUHPPAState *env = &cpu->env; | |
200 | ||
1a19da0d | 201 | cs->exception_index = -1; |
61766fe9 | 202 | cpu_hppa_loaded_fr0(env); |
1a19da0d | 203 | cpu_hppa_put_psw(env, PSW_W); |
61766fe9 RH |
204 | } |
205 | ||
8fc24ad5 | 206 | static ObjectClass *hppa_cpu_class_by_name(const char *cpu_model) |
61766fe9 | 207 | { |
ca4c2008 | 208 | g_autofree char *typename = g_strconcat(cpu_model, "-cpu", NULL); |
ca4c2008 | 209 | |
d5be19f5 | 210 | return object_class_by_name(typename); |
61766fe9 RH |
211 | } |
212 | ||
8b80bd28 PMD |
213 | #ifndef CONFIG_USER_ONLY |
214 | #include "hw/core/sysemu-cpu-ops.h" | |
215 | ||
216 | static const struct SysemuCPUOps hppa_sysemu_ops = { | |
08928c6d | 217 | .get_phys_page_debug = hppa_cpu_get_phys_page_debug, |
8b80bd28 PMD |
218 | }; |
219 | #endif | |
220 | ||
78271684 CF |
221 | #include "hw/core/tcg-cpu-ops.h" |
222 | ||
1764ad70 | 223 | static const TCGCPUOps hppa_tcg_ops = { |
78271684 CF |
224 | .initialize = hppa_translate_init, |
225 | .synchronize_from_tb = hppa_cpu_synchronize_from_tb, | |
e9cc3aca | 226 | .restore_state_to_opc = hppa_restore_state_to_opc, |
78271684 CF |
227 | |
228 | #ifndef CONFIG_USER_ONLY | |
860e0b96 | 229 | .tlb_fill = hppa_cpu_tlb_fill, |
68fa1780 | 230 | .cpu_exec_interrupt = hppa_cpu_exec_interrupt, |
78271684 CF |
231 | .do_interrupt = hppa_cpu_do_interrupt, |
232 | .do_unaligned_access = hppa_cpu_do_unaligned_access, | |
9ccbe394 | 233 | .do_transaction_failed = hppa_cpu_do_transaction_failed, |
78271684 CF |
234 | #endif /* !CONFIG_USER_ONLY */ |
235 | }; | |
236 | ||
61766fe9 RH |
237 | static void hppa_cpu_class_init(ObjectClass *oc, void *data) |
238 | { | |
239 | DeviceClass *dc = DEVICE_CLASS(oc); | |
240 | CPUClass *cc = CPU_CLASS(oc); | |
241 | HPPACPUClass *acc = HPPA_CPU_CLASS(oc); | |
242 | ||
bf853881 PMD |
243 | device_class_set_parent_realize(dc, hppa_cpu_realizefn, |
244 | &acc->parent_realize); | |
61766fe9 | 245 | |
8fc24ad5 | 246 | cc->class_by_name = hppa_cpu_class_by_name; |
4f5f2548 | 247 | cc->has_work = hppa_cpu_has_work; |
8f39cb77 | 248 | cc->mmu_index = hppa_cpu_mmu_index; |
61766fe9 RH |
249 | cc->dump_state = hppa_cpu_dump_state; |
250 | cc->set_pc = hppa_cpu_set_pc; | |
e4fdf9df | 251 | cc->get_pc = hppa_cpu_get_pc; |
61766fe9 RH |
252 | cc->gdb_read_register = hppa_cpu_gdb_read_register; |
253 | cc->gdb_write_register = hppa_cpu_gdb_write_register; | |
3c7bef03 | 254 | #ifndef CONFIG_USER_ONLY |
c643603a | 255 | dc->vmsd = &vmstate_hppa_cpu; |
8b80bd28 | 256 | cc->sysemu_ops = &hppa_sysemu_ops; |
813dff13 | 257 | #endif |
61766fe9 | 258 | cc->disas_set_info = hppa_cpu_disas_set_info; |
61766fe9 | 259 | cc->gdb_num_core_regs = 128; |
78271684 | 260 | cc->tcg_ops = &hppa_tcg_ops; |
61766fe9 RH |
261 | } |
262 | ||
bd6243a3 RH |
263 | static const TypeInfo hppa_cpu_type_infos[] = { |
264 | { | |
265 | .name = TYPE_HPPA_CPU, | |
266 | .parent = TYPE_CPU, | |
267 | .instance_size = sizeof(HPPACPU), | |
268 | .instance_align = __alignof(HPPACPU), | |
269 | .instance_init = hppa_cpu_initfn, | |
270 | .abstract = false, | |
271 | .class_size = sizeof(HPPACPUClass), | |
272 | .class_init = hppa_cpu_class_init, | |
273 | }, | |
bd6243a3 RH |
274 | { |
275 | .name = TYPE_HPPA64_CPU, | |
276 | .parent = TYPE_HPPA_CPU, | |
277 | }, | |
61766fe9 RH |
278 | }; |
279 | ||
bd6243a3 | 280 | DEFINE_TYPES(hppa_cpu_type_infos) |