]> git.proxmox.com Git - mirror_qemu.git/blob - target/mips/internal.h
mips: introduce internal.h and cleanup cpu.h
[mirror_qemu.git] / target / mips / internal.h
1 /* mips internal definitions and helpers
2 *
3 * This work is licensed under the terms of the GNU GPL, version 2 or later.
4 * See the COPYING file in the top-level directory.
5 */
6
7 #ifndef MIPS_INTERNAL_H
8 #define MIPS_INTERNAL_H
9
10 enum CPUMIPSMSADataFormat {
11 DF_BYTE = 0,
12 DF_HALF,
13 DF_WORD,
14 DF_DOUBLE
15 };
16
17 void mips_cpu_do_interrupt(CPUState *cpu);
18 bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
19 void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
20 int flags);
21 hwaddr mips_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
22 int mips_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
23 int mips_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
24 void mips_cpu_do_unaligned_access(CPUState *cpu, vaddr addr,
25 MMUAccessType access_type,
26 int mmu_idx, uintptr_t retaddr);
27
28 #if !defined(CONFIG_USER_ONLY)
29
30 typedef struct r4k_tlb_t r4k_tlb_t;
31 struct r4k_tlb_t {
32 target_ulong VPN;
33 uint32_t PageMask;
34 uint16_t ASID;
35 unsigned int G:1;
36 unsigned int C0:3;
37 unsigned int C1:3;
38 unsigned int V0:1;
39 unsigned int V1:1;
40 unsigned int D0:1;
41 unsigned int D1:1;
42 unsigned int XI0:1;
43 unsigned int XI1:1;
44 unsigned int RI0:1;
45 unsigned int RI1:1;
46 unsigned int EHINV:1;
47 uint64_t PFN[2];
48 };
49
50 struct CPUMIPSTLBContext {
51 uint32_t nb_tlb;
52 uint32_t tlb_in_use;
53 int (*map_address)(struct CPUMIPSState *env, hwaddr *physical, int *prot,
54 target_ulong address, int rw, int access_type);
55 void (*helper_tlbwi)(struct CPUMIPSState *env);
56 void (*helper_tlbwr)(struct CPUMIPSState *env);
57 void (*helper_tlbp)(struct CPUMIPSState *env);
58 void (*helper_tlbr)(struct CPUMIPSState *env);
59 void (*helper_tlbinv)(struct CPUMIPSState *env);
60 void (*helper_tlbinvf)(struct CPUMIPSState *env);
61 union {
62 struct {
63 r4k_tlb_t tlb[MIPS_TLB_MAX];
64 } r4k;
65 } mmu;
66 };
67
68 int no_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
69 target_ulong address, int rw, int access_type);
70 int fixed_mmu_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
71 target_ulong address, int rw, int access_type);
72 int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
73 target_ulong address, int rw, int access_type);
74 void r4k_helper_tlbwi(CPUMIPSState *env);
75 void r4k_helper_tlbwr(CPUMIPSState *env);
76 void r4k_helper_tlbp(CPUMIPSState *env);
77 void r4k_helper_tlbr(CPUMIPSState *env);
78 void r4k_helper_tlbinv(CPUMIPSState *env);
79 void r4k_helper_tlbinvf(CPUMIPSState *env);
80 void r4k_invalidate_tlb(CPUMIPSState *env, int idx, int use_extra);
81
82 void mips_cpu_unassigned_access(CPUState *cpu, hwaddr addr,
83 bool is_write, bool is_exec, int unused,
84 unsigned size);
85 hwaddr cpu_mips_translate_address(CPUMIPSState *env, target_ulong address,
86 int rw);
87 #endif
88
89 #define cpu_signal_handler cpu_mips_signal_handler
90
91 #ifndef CONFIG_USER_ONLY
92 extern const struct VMStateDescription vmstate_mips_cpu;
93 #endif
94
95 static inline bool cpu_mips_hw_interrupts_enabled(CPUMIPSState *env)
96 {
97 return (env->CP0_Status & (1 << CP0St_IE)) &&
98 !(env->CP0_Status & (1 << CP0St_EXL)) &&
99 !(env->CP0_Status & (1 << CP0St_ERL)) &&
100 !(env->hflags & MIPS_HFLAG_DM) &&
101 /* Note that the TCStatus IXMT field is initialized to zero,
102 and only MT capable cores can set it to one. So we don't
103 need to check for MT capabilities here. */
104 !(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_IXMT));
105 }
106
107 /* Check if there is pending and not masked out interrupt */
108 static inline bool cpu_mips_hw_interrupts_pending(CPUMIPSState *env)
109 {
110 int32_t pending;
111 int32_t status;
112 bool r;
113
114 pending = env->CP0_Cause & CP0Ca_IP_mask;
115 status = env->CP0_Status & CP0Ca_IP_mask;
116
117 if (env->CP0_Config3 & (1 << CP0C3_VEIC)) {
118 /* A MIPS configured with a vectorizing external interrupt controller
119 will feed a vector into the Cause pending lines. The core treats
120 the status lines as a vector level, not as indiviual masks. */
121 r = pending > status;
122 } else {
123 /* A MIPS configured with compatibility or VInt (Vectored Interrupts)
124 treats the pending lines as individual interrupt lines, the status
125 lines are individual masks. */
126 r = (pending & status) != 0;
127 }
128 return r;
129 }
130
131 void mips_tcg_init(void);
132
133 /* TODO QOM'ify CPU reset and remove */
134 void cpu_state_reset(CPUMIPSState *s);
135
136 /* cp0_timer.c */
137 uint32_t cpu_mips_get_random(CPUMIPSState *env);
138 uint32_t cpu_mips_get_count(CPUMIPSState *env);
139 void cpu_mips_store_count(CPUMIPSState *env, uint32_t value);
140 void cpu_mips_store_compare(CPUMIPSState *env, uint32_t value);
141 void cpu_mips_start_count(CPUMIPSState *env);
142 void cpu_mips_stop_count(CPUMIPSState *env);
143
144 /* helper.c */
145 int mips_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
146 int mmu_idx);
147
148 /* op_helper.c */
149 uint32_t float_class_s(uint32_t arg, float_status *fst);
150 uint64_t float_class_d(uint64_t arg, float_status *fst);
151
152 extern unsigned int ieee_rm[];
153 int ieee_ex_to_mips(int xcpt);
154
155 static inline void restore_rounding_mode(CPUMIPSState *env)
156 {
157 set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3],
158 &env->active_fpu.fp_status);
159 }
160
161 static inline void restore_flush_mode(CPUMIPSState *env)
162 {
163 set_flush_to_zero((env->active_fpu.fcr31 & (1 << FCR31_FS)) != 0,
164 &env->active_fpu.fp_status);
165 }
166
167 static inline void restore_fp_status(CPUMIPSState *env)
168 {
169 restore_rounding_mode(env);
170 restore_flush_mode(env);
171 restore_snan_bit_mode(env);
172 }
173
174 static inline void restore_msa_fp_status(CPUMIPSState *env)
175 {
176 float_status *status = &env->active_tc.msa_fp_status;
177 int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM;
178 bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0;
179
180 set_float_rounding_mode(ieee_rm[rounding_mode], status);
181 set_flush_to_zero(flush_to_zero, status);
182 set_flush_inputs_to_zero(flush_to_zero, status);
183 }
184
185 static inline void restore_pamask(CPUMIPSState *env)
186 {
187 if (env->hflags & MIPS_HFLAG_ELPA) {
188 env->PAMask = (1ULL << env->PABITS) - 1;
189 } else {
190 env->PAMask = PAMASK_BASE;
191 }
192 }
193
194 static inline int mips_vpe_active(CPUMIPSState *env)
195 {
196 int active = 1;
197
198 /* Check that the VPE is enabled. */
199 if (!(env->mvp->CP0_MVPControl & (1 << CP0MVPCo_EVP))) {
200 active = 0;
201 }
202 /* Check that the VPE is activated. */
203 if (!(env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))) {
204 active = 0;
205 }
206
207 /* Now verify that there are active thread contexts in the VPE.
208
209 This assumes the CPU model will internally reschedule threads
210 if the active one goes to sleep. If there are no threads available
211 the active one will be in a sleeping state, and we can turn off
212 the entire VPE. */
213 if (!(env->active_tc.CP0_TCStatus & (1 << CP0TCSt_A))) {
214 /* TC is not activated. */
215 active = 0;
216 }
217 if (env->active_tc.CP0_TCHalt & 1) {
218 /* TC is in halt state. */
219 active = 0;
220 }
221
222 return active;
223 }
224
225 static inline int mips_vp_active(CPUMIPSState *env)
226 {
227 CPUState *other_cs = first_cpu;
228
229 /* Check if the VP disabled other VPs (which means the VP is enabled) */
230 if ((env->CP0_VPControl >> CP0VPCtl_DIS) & 1) {
231 return 1;
232 }
233
234 /* Check if the virtual processor is disabled due to a DVP */
235 CPU_FOREACH(other_cs) {
236 MIPSCPU *other_cpu = MIPS_CPU(other_cs);
237 if ((&other_cpu->env != env) &&
238 ((other_cpu->env.CP0_VPControl >> CP0VPCtl_DIS) & 1)) {
239 return 0;
240 }
241 }
242 return 1;
243 }
244
245 static inline void compute_hflags(CPUMIPSState *env)
246 {
247 env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 |
248 MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU |
249 MIPS_HFLAG_AWRAP | MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2 |
250 MIPS_HFLAG_SBRI | MIPS_HFLAG_MSA | MIPS_HFLAG_FRE |
251 MIPS_HFLAG_ELPA | MIPS_HFLAG_ERL);
252 if (env->CP0_Status & (1 << CP0St_ERL)) {
253 env->hflags |= MIPS_HFLAG_ERL;
254 }
255 if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
256 !(env->CP0_Status & (1 << CP0St_ERL)) &&
257 !(env->hflags & MIPS_HFLAG_DM)) {
258 env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU;
259 }
260 #if defined(TARGET_MIPS64)
261 if ((env->insn_flags & ISA_MIPS3) &&
262 (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) ||
263 (env->CP0_Status & (1 << CP0St_PX)) ||
264 (env->CP0_Status & (1 << CP0St_UX)))) {
265 env->hflags |= MIPS_HFLAG_64;
266 }
267
268 if (!(env->insn_flags & ISA_MIPS3)) {
269 env->hflags |= MIPS_HFLAG_AWRAP;
270 } else if (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_UM) &&
271 !(env->CP0_Status & (1 << CP0St_UX))) {
272 env->hflags |= MIPS_HFLAG_AWRAP;
273 } else if (env->insn_flags & ISA_MIPS64R6) {
274 /* Address wrapping for Supervisor and Kernel is specified in R6 */
275 if ((((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_SM) &&
276 !(env->CP0_Status & (1 << CP0St_SX))) ||
277 (((env->hflags & MIPS_HFLAG_KSU) == MIPS_HFLAG_KM) &&
278 !(env->CP0_Status & (1 << CP0St_KX)))) {
279 env->hflags |= MIPS_HFLAG_AWRAP;
280 }
281 }
282 #endif
283 if (((env->CP0_Status & (1 << CP0St_CU0)) &&
284 !(env->insn_flags & ISA_MIPS32R6)) ||
285 !(env->hflags & MIPS_HFLAG_KSU)) {
286 env->hflags |= MIPS_HFLAG_CP0;
287 }
288 if (env->CP0_Status & (1 << CP0St_CU1)) {
289 env->hflags |= MIPS_HFLAG_FPU;
290 }
291 if (env->CP0_Status & (1 << CP0St_FR)) {
292 env->hflags |= MIPS_HFLAG_F64;
293 }
294 if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_KM) &&
295 (env->CP0_Config5 & (1 << CP0C5_SBRI))) {
296 env->hflags |= MIPS_HFLAG_SBRI;
297 }
298 if (env->insn_flags & ASE_DSPR2) {
299 /* Enables access MIPS DSP resources, now our cpu is DSP ASER2,
300 so enable to access DSPR2 resources. */
301 if (env->CP0_Status & (1 << CP0St_MX)) {
302 env->hflags |= MIPS_HFLAG_DSP | MIPS_HFLAG_DSPR2;
303 }
304
305 } else if (env->insn_flags & ASE_DSP) {
306 /* Enables access MIPS DSP resources, now our cpu is DSP ASE,
307 so enable to access DSP resources. */
308 if (env->CP0_Status & (1 << CP0St_MX)) {
309 env->hflags |= MIPS_HFLAG_DSP;
310 }
311
312 }
313 if (env->insn_flags & ISA_MIPS32R2) {
314 if (env->active_fpu.fcr0 & (1 << FCR0_F64)) {
315 env->hflags |= MIPS_HFLAG_COP1X;
316 }
317 } else if (env->insn_flags & ISA_MIPS32) {
318 if (env->hflags & MIPS_HFLAG_64) {
319 env->hflags |= MIPS_HFLAG_COP1X;
320 }
321 } else if (env->insn_flags & ISA_MIPS4) {
322 /* All supported MIPS IV CPUs use the XX (CU3) to enable
323 and disable the MIPS IV extensions to the MIPS III ISA.
324 Some other MIPS IV CPUs ignore the bit, so the check here
325 would be too restrictive for them. */
326 if (env->CP0_Status & (1U << CP0St_CU3)) {
327 env->hflags |= MIPS_HFLAG_COP1X;
328 }
329 }
330 if (env->insn_flags & ASE_MSA) {
331 if (env->CP0_Config5 & (1 << CP0C5_MSAEn)) {
332 env->hflags |= MIPS_HFLAG_MSA;
333 }
334 }
335 if (env->active_fpu.fcr0 & (1 << FCR0_FREP)) {
336 if (env->CP0_Config5 & (1 << CP0C5_FRE)) {
337 env->hflags |= MIPS_HFLAG_FRE;
338 }
339 }
340 if (env->CP0_Config3 & (1 << CP0C3_LPA)) {
341 if (env->CP0_PageGrain & (1 << CP0PG_ELPA)) {
342 env->hflags |= MIPS_HFLAG_ELPA;
343 }
344 }
345 }
346
347 void cpu_mips_tlb_flush(CPUMIPSState *env);
348 void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc);
349 void cpu_mips_store_status(CPUMIPSState *env, target_ulong val);
350 void cpu_mips_store_cause(CPUMIPSState *env, target_ulong val);
351
352 void QEMU_NORETURN do_raise_exception_err(CPUMIPSState *env, uint32_t exception,
353 int error_code, uintptr_t pc);
354
355 static inline void QEMU_NORETURN do_raise_exception(CPUMIPSState *env,
356 uint32_t exception,
357 uintptr_t pc)
358 {
359 do_raise_exception_err(env, exception, 0, pc);
360 }
361
362 #endif