]> git.proxmox.com Git - mirror_qemu.git/blob - target/cris/op_helper.c
target/cris: Convert to CPUClass::tlb_fill
[mirror_qemu.git] / target / cris / op_helper.c
1 /*
2 * CRIS helper routines
3 *
4 * Copyright (c) 2007 AXIS Communications
5 * Written by Edgar E. Iglesias
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "mmu.h"
24 #include "exec/helper-proto.h"
25 #include "qemu/host-utils.h"
26 #include "exec/exec-all.h"
27 #include "exec/cpu_ldst.h"
28
29 //#define CRIS_OP_HELPER_DEBUG
30
31
32 #ifdef CRIS_OP_HELPER_DEBUG
33 #define D(x) x
34 #define D_LOG(...) qemu_log(__VA_ARGS__)
35 #else
36 #define D(x)
37 #define D_LOG(...) do { } while (0)
38 #endif
39
40 void helper_raise_exception(CPUCRISState *env, uint32_t index)
41 {
42 CPUState *cs = CPU(cris_env_get_cpu(env));
43
44 cs->exception_index = index;
45 cpu_loop_exit(cs);
46 }
47
48 void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid)
49 {
50 #if !defined(CONFIG_USER_ONLY)
51 pid &= 0xff;
52 if (pid != (env->pregs[PR_PID] & 0xff))
53 cris_mmu_flush_pid(env, env->pregs[PR_PID]);
54 #endif
55 }
56
57 void helper_spc_write(CPUCRISState *env, uint32_t new_spc)
58 {
59 #if !defined(CONFIG_USER_ONLY)
60 CRISCPU *cpu = cris_env_get_cpu(env);
61 CPUState *cs = CPU(cpu);
62
63 tlb_flush_page(cs, env->pregs[PR_SPC]);
64 tlb_flush_page(cs, new_spc);
65 #endif
66 }
67
68 /* Used by the tlb decoder. */
69 #define EXTRACT_FIELD(src, start, end) \
70 (((src) >> start) & ((1 << (end - start + 1)) - 1))
71
72 void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg)
73 {
74 #if !defined(CONFIG_USER_ONLY)
75 CRISCPU *cpu = cris_env_get_cpu(env);
76 #endif
77 uint32_t srs;
78 srs = env->pregs[PR_SRS];
79 srs &= 3;
80 env->sregs[srs][sreg] = env->regs[reg];
81
82 #if !defined(CONFIG_USER_ONLY)
83 if (srs == 1 || srs == 2) {
84 if (sreg == 6) {
85 /* Writes to tlb-hi write to mm_cause as a side
86 effect. */
87 env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg];
88 env->sregs[SFR_R_MM_CAUSE] = env->regs[reg];
89 }
90 else if (sreg == 5) {
91 uint32_t set;
92 uint32_t idx;
93 uint32_t lo, hi;
94 uint32_t vaddr;
95 int tlb_v;
96
97 idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
98 set >>= 4;
99 set &= 3;
100
101 idx &= 15;
102 /* We've just made a write to tlb_lo. */
103 lo = env->sregs[SFR_RW_MM_TLB_LO];
104 /* Writes are done via r_mm_cause. */
105 hi = env->sregs[SFR_R_MM_CAUSE];
106
107 vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi,
108 13, 31);
109 vaddr <<= TARGET_PAGE_BITS;
110 tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo,
111 3, 3);
112 env->tlbsets[srs - 1][set][idx].lo = lo;
113 env->tlbsets[srs - 1][set][idx].hi = hi;
114
115 D_LOG("tlb flush vaddr=%x v=%d pc=%x\n",
116 vaddr, tlb_v, env->pc);
117 if (tlb_v) {
118 tlb_flush_page(CPU(cpu), vaddr);
119 }
120 }
121 }
122 #endif
123 }
124
125 void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg)
126 {
127 uint32_t srs;
128 env->pregs[PR_SRS] &= 3;
129 srs = env->pregs[PR_SRS];
130
131 #if !defined(CONFIG_USER_ONLY)
132 if (srs == 1 || srs == 2)
133 {
134 uint32_t set;
135 uint32_t idx;
136 uint32_t lo, hi;
137
138 idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
139 set >>= 4;
140 set &= 3;
141 idx &= 15;
142
143 /* Update the mirror regs. */
144 hi = env->tlbsets[srs - 1][set][idx].hi;
145 lo = env->tlbsets[srs - 1][set][idx].lo;
146 env->sregs[SFR_RW_MM_TLB_HI] = hi;
147 env->sregs[SFR_RW_MM_TLB_LO] = lo;
148 }
149 #endif
150 env->regs[reg] = env->sregs[srs][sreg];
151 }
152
153 static void cris_ccs_rshift(CPUCRISState *env)
154 {
155 uint32_t ccs;
156
157 /* Apply the ccs shift. */
158 ccs = env->pregs[PR_CCS];
159 ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
160 if (ccs & U_FLAG)
161 {
162 /* Enter user mode. */
163 env->ksp = env->regs[R_SP];
164 env->regs[R_SP] = env->pregs[PR_USP];
165 }
166
167 env->pregs[PR_CCS] = ccs;
168 }
169
170 void helper_rfe(CPUCRISState *env)
171 {
172 int rflag = env->pregs[PR_CCS] & R_FLAG;
173
174 D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n",
175 env->pregs[PR_ERP], env->pregs[PR_PID],
176 env->pregs[PR_CCS],
177 env->btarget);
178
179 cris_ccs_rshift(env);
180
181 /* RFE sets the P_FLAG only if the R_FLAG is not set. */
182 if (!rflag)
183 env->pregs[PR_CCS] |= P_FLAG;
184 }
185
186 void helper_rfn(CPUCRISState *env)
187 {
188 int rflag = env->pregs[PR_CCS] & R_FLAG;
189
190 D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n",
191 env->pregs[PR_ERP], env->pregs[PR_PID],
192 env->pregs[PR_CCS],
193 env->btarget);
194
195 cris_ccs_rshift(env);
196
197 /* Set the P_FLAG only if the R_FLAG is not set. */
198 if (!rflag)
199 env->pregs[PR_CCS] |= P_FLAG;
200
201 /* Always set the M flag. */
202 env->pregs[PR_CCS] |= M_FLAG_V32;
203 }
204
205 uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs)
206 {
207 /* FIXME: clean this up. */
208
209 /* des ref:
210 The N flag is set according to the selected bit in the dest reg.
211 The Z flag is set if the selected bit and all bits to the right are
212 zero.
213 The X flag is cleared.
214 Other flags are left untouched.
215 The destination reg is not affected.*/
216 unsigned int fz, sbit, bset, mask, masked_t0;
217
218 sbit = t1 & 31;
219 bset = !!(t0 & (1 << sbit));
220 mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1;
221 masked_t0 = t0 & mask;
222 fz = !(masked_t0 | bset);
223
224 /* Clear the X, N and Z flags. */
225 ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG);
226 if (env->pregs[PR_VR] < 32)
227 ccs &= ~(V_FLAG | C_FLAG);
228 /* Set the N and Z flags accordingly. */
229 ccs |= (bset << 3) | (fz << 2);
230 return ccs;
231 }
232
233 static inline uint32_t evaluate_flags_writeback(CPUCRISState *env,
234 uint32_t flags, uint32_t ccs)
235 {
236 unsigned int x, z, mask;
237
238 /* Extended arithmetics, leave the z flag alone. */
239 x = env->cc_x;
240 mask = env->cc_mask | X_FLAG;
241 if (x) {
242 z = flags & Z_FLAG;
243 mask = mask & ~z;
244 }
245 flags &= mask;
246
247 /* all insn clear the x-flag except setf or clrf. */
248 ccs &= ~mask;
249 ccs |= flags;
250 return ccs;
251 }
252
253 uint32_t helper_evaluate_flags_muls(CPUCRISState *env,
254 uint32_t ccs, uint32_t res, uint32_t mof)
255 {
256 uint32_t flags = 0;
257 int64_t tmp;
258 int dneg;
259
260 dneg = ((int32_t)res) < 0;
261
262 tmp = mof;
263 tmp <<= 32;
264 tmp |= res;
265 if (tmp == 0)
266 flags |= Z_FLAG;
267 else if (tmp < 0)
268 flags |= N_FLAG;
269 if ((dneg && mof != -1)
270 || (!dneg && mof != 0))
271 flags |= V_FLAG;
272 return evaluate_flags_writeback(env, flags, ccs);
273 }
274
275 uint32_t helper_evaluate_flags_mulu(CPUCRISState *env,
276 uint32_t ccs, uint32_t res, uint32_t mof)
277 {
278 uint32_t flags = 0;
279 uint64_t tmp;
280
281 tmp = mof;
282 tmp <<= 32;
283 tmp |= res;
284 if (tmp == 0)
285 flags |= Z_FLAG;
286 else if (tmp >> 63)
287 flags |= N_FLAG;
288 if (mof)
289 flags |= V_FLAG;
290
291 return evaluate_flags_writeback(env, flags, ccs);
292 }
293
294 uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs,
295 uint32_t src, uint32_t dst, uint32_t res)
296 {
297 uint32_t flags = 0;
298
299 src = src & 0x80000000;
300 dst = dst & 0x80000000;
301
302 if ((res & 0x80000000L) != 0L)
303 {
304 flags |= N_FLAG;
305 if (!src && !dst)
306 flags |= V_FLAG;
307 else if (src & dst)
308 flags |= R_FLAG;
309 }
310 else
311 {
312 if (res == 0L)
313 flags |= Z_FLAG;
314 if (src & dst)
315 flags |= V_FLAG;
316 if (dst | src)
317 flags |= R_FLAG;
318 }
319
320 return evaluate_flags_writeback(env, flags, ccs);
321 }
322
323 uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs,
324 uint32_t src, uint32_t dst, uint32_t res)
325 {
326 uint32_t flags = 0;
327
328 src = src & 0x80000000;
329 dst = dst & 0x80000000;
330
331 if ((res & 0x80000000L) != 0L)
332 {
333 flags |= N_FLAG;
334 if (!src && !dst)
335 flags |= V_FLAG;
336 else if (src & dst)
337 flags |= C_FLAG;
338 }
339 else
340 {
341 if (res == 0L)
342 flags |= Z_FLAG;
343 if (src & dst)
344 flags |= V_FLAG;
345 if (dst | src)
346 flags |= C_FLAG;
347 }
348
349 return evaluate_flags_writeback(env, flags, ccs);
350 }
351
352 uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs,
353 uint32_t src, uint32_t dst, uint32_t res)
354 {
355 uint32_t flags = 0;
356
357 src = (~src) & 0x80000000;
358 dst = dst & 0x80000000;
359
360 if ((res & 0x80000000L) != 0L)
361 {
362 flags |= N_FLAG;
363 if (!src && !dst)
364 flags |= V_FLAG;
365 else if (src & dst)
366 flags |= C_FLAG;
367 }
368 else
369 {
370 if (res == 0L)
371 flags |= Z_FLAG;
372 if (src & dst)
373 flags |= V_FLAG;
374 if (dst | src)
375 flags |= C_FLAG;
376 }
377
378 flags ^= C_FLAG;
379 return evaluate_flags_writeback(env, flags, ccs);
380 }
381
382 uint32_t helper_evaluate_flags_move_4(CPUCRISState *env,
383 uint32_t ccs, uint32_t res)
384 {
385 uint32_t flags = 0;
386
387 if ((int32_t)res < 0)
388 flags |= N_FLAG;
389 else if (res == 0L)
390 flags |= Z_FLAG;
391
392 return evaluate_flags_writeback(env, flags, ccs);
393 }
394 uint32_t helper_evaluate_flags_move_2(CPUCRISState *env,
395 uint32_t ccs, uint32_t res)
396 {
397 uint32_t flags = 0;
398
399 if ((int16_t)res < 0L)
400 flags |= N_FLAG;
401 else if (res == 0)
402 flags |= Z_FLAG;
403
404 return evaluate_flags_writeback(env, flags, ccs);
405 }
406
407 /* TODO: This is expensive. We could split things up and only evaluate part of
408 CCR on a need to know basis. For now, we simply re-evaluate everything. */
409 void helper_evaluate_flags(CPUCRISState *env)
410 {
411 uint32_t src, dst, res;
412 uint32_t flags = 0;
413
414 src = env->cc_src;
415 dst = env->cc_dest;
416 res = env->cc_result;
417
418 if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
419 src = ~src;
420
421 /* Now, evaluate the flags. This stuff is based on
422 Per Zander's CRISv10 simulator. */
423 switch (env->cc_size)
424 {
425 case 1:
426 if ((res & 0x80L) != 0L)
427 {
428 flags |= N_FLAG;
429 if (((src & 0x80L) == 0L)
430 && ((dst & 0x80L) == 0L))
431 {
432 flags |= V_FLAG;
433 }
434 else if (((src & 0x80L) != 0L)
435 && ((dst & 0x80L) != 0L))
436 {
437 flags |= C_FLAG;
438 }
439 }
440 else
441 {
442 if ((res & 0xFFL) == 0L)
443 {
444 flags |= Z_FLAG;
445 }
446 if (((src & 0x80L) != 0L)
447 && ((dst & 0x80L) != 0L))
448 {
449 flags |= V_FLAG;
450 }
451 if ((dst & 0x80L) != 0L
452 || (src & 0x80L) != 0L)
453 {
454 flags |= C_FLAG;
455 }
456 }
457 break;
458 case 2:
459 if ((res & 0x8000L) != 0L)
460 {
461 flags |= N_FLAG;
462 if (((src & 0x8000L) == 0L)
463 && ((dst & 0x8000L) == 0L))
464 {
465 flags |= V_FLAG;
466 }
467 else if (((src & 0x8000L) != 0L)
468 && ((dst & 0x8000L) != 0L))
469 {
470 flags |= C_FLAG;
471 }
472 }
473 else
474 {
475 if ((res & 0xFFFFL) == 0L)
476 {
477 flags |= Z_FLAG;
478 }
479 if (((src & 0x8000L) != 0L)
480 && ((dst & 0x8000L) != 0L))
481 {
482 flags |= V_FLAG;
483 }
484 if ((dst & 0x8000L) != 0L
485 || (src & 0x8000L) != 0L)
486 {
487 flags |= C_FLAG;
488 }
489 }
490 break;
491 case 4:
492 if ((res & 0x80000000L) != 0L)
493 {
494 flags |= N_FLAG;
495 if (((src & 0x80000000L) == 0L)
496 && ((dst & 0x80000000L) == 0L))
497 {
498 flags |= V_FLAG;
499 }
500 else if (((src & 0x80000000L) != 0L) &&
501 ((dst & 0x80000000L) != 0L))
502 {
503 flags |= C_FLAG;
504 }
505 }
506 else
507 {
508 if (res == 0L)
509 flags |= Z_FLAG;
510 if (((src & 0x80000000L) != 0L)
511 && ((dst & 0x80000000L) != 0L))
512 flags |= V_FLAG;
513 if ((dst & 0x80000000L) != 0L
514 || (src & 0x80000000L) != 0L)
515 flags |= C_FLAG;
516 }
517 break;
518 default:
519 break;
520 }
521
522 if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
523 flags ^= C_FLAG;
524
525 env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags,
526 env->pregs[PR_CCS]);
527 }
528
529 void helper_top_evaluate_flags(CPUCRISState *env)
530 {
531 switch (env->cc_op)
532 {
533 case CC_OP_MCP:
534 env->pregs[PR_CCS] = helper_evaluate_flags_mcp(env,
535 env->pregs[PR_CCS], env->cc_src,
536 env->cc_dest, env->cc_result);
537 break;
538 case CC_OP_MULS:
539 env->pregs[PR_CCS] = helper_evaluate_flags_muls(env,
540 env->pregs[PR_CCS], env->cc_result,
541 env->pregs[PR_MOF]);
542 break;
543 case CC_OP_MULU:
544 env->pregs[PR_CCS] = helper_evaluate_flags_mulu(env,
545 env->pregs[PR_CCS], env->cc_result,
546 env->pregs[PR_MOF]);
547 break;
548 case CC_OP_MOVE:
549 case CC_OP_AND:
550 case CC_OP_OR:
551 case CC_OP_XOR:
552 case CC_OP_ASR:
553 case CC_OP_LSR:
554 case CC_OP_LSL:
555 switch (env->cc_size)
556 {
557 case 4:
558 env->pregs[PR_CCS] =
559 helper_evaluate_flags_move_4(env,
560 env->pregs[PR_CCS],
561 env->cc_result);
562 break;
563 case 2:
564 env->pregs[PR_CCS] =
565 helper_evaluate_flags_move_2(env,
566 env->pregs[PR_CCS],
567 env->cc_result);
568 break;
569 default:
570 helper_evaluate_flags(env);
571 break;
572 }
573 break;
574 case CC_OP_FLAGS:
575 /* live. */
576 break;
577 case CC_OP_SUB:
578 case CC_OP_CMP:
579 if (env->cc_size == 4)
580 env->pregs[PR_CCS] =
581 helper_evaluate_flags_sub_4(env,
582 env->pregs[PR_CCS],
583 env->cc_src, env->cc_dest,
584 env->cc_result);
585 else
586 helper_evaluate_flags(env);
587 break;
588 default:
589 {
590 switch (env->cc_size)
591 {
592 case 4:
593 env->pregs[PR_CCS] =
594 helper_evaluate_flags_alu_4(env,
595 env->pregs[PR_CCS],
596 env->cc_src, env->cc_dest,
597 env->cc_result);
598 break;
599 default:
600 helper_evaluate_flags(env);
601 break;
602 }
603 }
604 break;
605 }
606 }