Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / target / cris / op_helper.c
blob98a9aaf50464c9d603534cf40dbb6677aede4d62
1 /*
2 * CRIS helper routines
4 * Copyright (c) 2007 AXIS Communications
5 * Written by Edgar E. Iglesias
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.1 of the License, or (at your option) any later version.
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.
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/>.
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"
28 //#define CRIS_OP_HELPER_DEBUG
31 #ifdef CRIS_OP_HELPER_DEBUG
32 #define D(x) x
33 #define D_LOG(...) qemu_log(__VA_ARGS__)
34 #else
35 #define D(x)
36 #define D_LOG(...) do { } while (0)
37 #endif
39 void helper_raise_exception(CPUCRISState *env, uint32_t index)
41 CPUState *cs = env_cpu(env);
43 cs->exception_index = index;
44 cpu_loop_exit(cs);
47 void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid)
49 #if !defined(CONFIG_USER_ONLY)
50 pid &= 0xff;
51 if (pid != (env->pregs[PR_PID] & 0xff)) {
52 cris_mmu_flush_pid(env, env->pregs[PR_PID]);
54 #endif
57 void helper_spc_write(CPUCRISState *env, uint32_t new_spc)
59 #if !defined(CONFIG_USER_ONLY)
60 CPUState *cs = env_cpu(env);
62 tlb_flush_page(cs, env->pregs[PR_SPC]);
63 tlb_flush_page(cs, new_spc);
64 #endif
67 /* Used by the tlb decoder. */
68 #define EXTRACT_FIELD(src, start, end) \
69 (((src) >> start) & ((1 << (end - start + 1)) - 1))
71 void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg)
73 uint32_t srs;
74 srs = env->pregs[PR_SRS];
75 srs &= 3;
76 env->sregs[srs][sreg] = env->regs[reg];
78 #if !defined(CONFIG_USER_ONLY)
79 if (srs == 1 || srs == 2) {
80 if (sreg == 6) {
81 /* Writes to tlb-hi write to mm_cause as a side effect. */
82 env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg];
83 env->sregs[SFR_R_MM_CAUSE] = env->regs[reg];
84 } else if (sreg == 5) {
85 uint32_t set;
86 uint32_t idx;
87 uint32_t lo, hi;
88 uint32_t vaddr;
89 int tlb_v;
91 idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
92 set >>= 4;
93 set &= 3;
95 idx &= 15;
96 /* We've just made a write to tlb_lo. */
97 lo = env->sregs[SFR_RW_MM_TLB_LO];
98 /* Writes are done via r_mm_cause. */
99 hi = env->sregs[SFR_R_MM_CAUSE];
101 vaddr = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].hi, 13, 31);
102 vaddr <<= TARGET_PAGE_BITS;
103 tlb_v = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].lo, 3, 3);
104 env->tlbsets[srs - 1][set][idx].lo = lo;
105 env->tlbsets[srs - 1][set][idx].hi = hi;
107 D_LOG("tlb flush vaddr=%x v=%d pc=%x\n",
108 vaddr, tlb_v, env->pc);
109 if (tlb_v) {
110 tlb_flush_page(env_cpu(env), vaddr);
114 #endif
117 void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg)
119 uint32_t srs;
120 env->pregs[PR_SRS] &= 3;
121 srs = env->pregs[PR_SRS];
123 #if !defined(CONFIG_USER_ONLY)
124 if (srs == 1 || srs == 2) {
125 uint32_t set;
126 uint32_t idx;
127 uint32_t lo, hi;
129 idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
130 set >>= 4;
131 set &= 3;
132 idx &= 15;
134 /* Update the mirror regs. */
135 hi = env->tlbsets[srs - 1][set][idx].hi;
136 lo = env->tlbsets[srs - 1][set][idx].lo;
137 env->sregs[SFR_RW_MM_TLB_HI] = hi;
138 env->sregs[SFR_RW_MM_TLB_LO] = lo;
140 #endif
141 env->regs[reg] = env->sregs[srs][sreg];
144 static void cris_ccs_rshift(CPUCRISState *env)
146 uint32_t ccs;
148 /* Apply the ccs shift. */
149 ccs = env->pregs[PR_CCS];
150 ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
151 if (ccs & U_FLAG) {
152 /* Enter user mode. */
153 env->ksp = env->regs[R_SP];
154 env->regs[R_SP] = env->pregs[PR_USP];
157 env->pregs[PR_CCS] = ccs;
160 void helper_rfe(CPUCRISState *env)
162 int rflag = env->pregs[PR_CCS] & R_FLAG;
164 D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n",
165 env->pregs[PR_ERP], env->pregs[PR_PID],
166 env->pregs[PR_CCS],
167 env->btarget);
169 cris_ccs_rshift(env);
171 /* RFE sets the P_FLAG only if the R_FLAG is not set. */
172 if (!rflag) {
173 env->pregs[PR_CCS] |= P_FLAG;
177 void helper_rfn(CPUCRISState *env)
179 int rflag = env->pregs[PR_CCS] & R_FLAG;
181 D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n",
182 env->pregs[PR_ERP], env->pregs[PR_PID],
183 env->pregs[PR_CCS],
184 env->btarget);
186 cris_ccs_rshift(env);
188 /* Set the P_FLAG only if the R_FLAG is not set. */
189 if (!rflag) {
190 env->pregs[PR_CCS] |= P_FLAG;
193 /* Always set the M flag. */
194 env->pregs[PR_CCS] |= M_FLAG_V32;
197 uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs)
199 /* FIXME: clean this up. */
202 * des ref:
203 * The N flag is set according to the selected bit in the dest reg.
204 * The Z flag is set if the selected bit and all bits to the right are
205 * zero.
206 * The X flag is cleared.
207 * Other flags are left untouched.
208 * The destination reg is not affected.
210 unsigned int fz, sbit, bset, mask, masked_t0;
212 sbit = t1 & 31;
213 bset = !!(t0 & (1 << sbit));
214 mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1;
215 masked_t0 = t0 & mask;
216 fz = !(masked_t0 | bset);
218 /* Clear the X, N and Z flags. */
219 ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG);
220 if (env->pregs[PR_VR] < 32) {
221 ccs &= ~(V_FLAG | C_FLAG);
223 /* Set the N and Z flags accordingly. */
224 ccs |= (bset << 3) | (fz << 2);
225 return ccs;
228 static inline uint32_t evaluate_flags_writeback(CPUCRISState *env,
229 uint32_t flags, uint32_t ccs)
231 unsigned int x, z, mask;
233 /* Extended arithmetic, leave the z flag alone. */
234 x = env->cc_x;
235 mask = env->cc_mask | X_FLAG;
236 if (x) {
237 z = flags & Z_FLAG;
238 mask = mask & ~z;
240 flags &= mask;
242 /* all insn clear the x-flag except setf or clrf. */
243 ccs &= ~mask;
244 ccs |= flags;
245 return ccs;
248 uint32_t helper_evaluate_flags_muls(CPUCRISState *env,
249 uint32_t ccs, uint32_t res, uint32_t mof)
251 uint32_t flags = 0;
252 int64_t tmp;
253 int dneg;
255 dneg = ((int32_t)res) < 0;
257 tmp = mof;
258 tmp <<= 32;
259 tmp |= res;
260 if (tmp == 0) {
261 flags |= Z_FLAG;
262 } else if (tmp < 0) {
263 flags |= N_FLAG;
265 if ((dneg && mof != -1) || (!dneg && mof != 0)) {
266 flags |= V_FLAG;
268 return evaluate_flags_writeback(env, flags, ccs);
271 uint32_t helper_evaluate_flags_mulu(CPUCRISState *env,
272 uint32_t ccs, uint32_t res, uint32_t mof)
274 uint32_t flags = 0;
275 uint64_t tmp;
277 tmp = mof;
278 tmp <<= 32;
279 tmp |= res;
280 if (tmp == 0) {
281 flags |= Z_FLAG;
282 } else if (tmp >> 63) {
283 flags |= N_FLAG;
285 if (mof) {
286 flags |= V_FLAG;
289 return evaluate_flags_writeback(env, flags, ccs);
292 uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs,
293 uint32_t src, uint32_t dst, uint32_t res)
295 uint32_t flags = 0;
297 src = src & 0x80000000;
298 dst = dst & 0x80000000;
300 if ((res & 0x80000000L) != 0L) {
301 flags |= N_FLAG;
302 if (!src && !dst) {
303 flags |= V_FLAG;
304 } else if (src & dst) {
305 flags |= R_FLAG;
307 } else {
308 if (res == 0L) {
309 flags |= Z_FLAG;
311 if (src & dst) {
312 flags |= V_FLAG;
314 if (dst | src) {
315 flags |= R_FLAG;
319 return evaluate_flags_writeback(env, flags, ccs);
322 uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs,
323 uint32_t src, uint32_t dst, uint32_t res)
325 uint32_t flags = 0;
327 src = src & 0x80000000;
328 dst = dst & 0x80000000;
330 if ((res & 0x80000000L) != 0L) {
331 flags |= N_FLAG;
332 if (!src && !dst) {
333 flags |= V_FLAG;
334 } else if (src & dst) {
335 flags |= C_FLAG;
337 } else {
338 if (res == 0L) {
339 flags |= Z_FLAG;
341 if (src & dst) {
342 flags |= V_FLAG;
344 if (dst | src) {
345 flags |= C_FLAG;
349 return evaluate_flags_writeback(env, flags, ccs);
352 uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs,
353 uint32_t src, uint32_t dst, uint32_t res)
355 uint32_t flags = 0;
357 src = (~src) & 0x80000000;
358 dst = dst & 0x80000000;
360 if ((res & 0x80000000L) != 0L) {
361 flags |= N_FLAG;
362 if (!src && !dst) {
363 flags |= V_FLAG;
364 } else if (src & dst) {
365 flags |= C_FLAG;
367 } else {
368 if (res == 0L) {
369 flags |= Z_FLAG;
371 if (src & dst) {
372 flags |= V_FLAG;
374 if (dst | src) {
375 flags |= C_FLAG;
379 flags ^= C_FLAG;
380 return evaluate_flags_writeback(env, flags, ccs);
383 uint32_t helper_evaluate_flags_move_4(CPUCRISState *env,
384 uint32_t ccs, uint32_t res)
386 uint32_t flags = 0;
388 if ((int32_t)res < 0) {
389 flags |= N_FLAG;
390 } else if (res == 0L) {
391 flags |= Z_FLAG;
394 return evaluate_flags_writeback(env, flags, ccs);
397 uint32_t helper_evaluate_flags_move_2(CPUCRISState *env,
398 uint32_t ccs, uint32_t res)
400 uint32_t flags = 0;
402 if ((int16_t)res < 0L) {
403 flags |= N_FLAG;
404 } else if (res == 0) {
405 flags |= Z_FLAG;
408 return evaluate_flags_writeback(env, flags, ccs);
412 * TODO: This is expensive. We could split things up and only evaluate part of
413 * CCR on a need to know basis. For now, we simply re-evaluate everything.
415 void helper_evaluate_flags(CPUCRISState *env)
417 uint32_t src, dst, res;
418 uint32_t flags = 0;
420 src = env->cc_src;
421 dst = env->cc_dest;
422 res = env->cc_result;
424 if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) {
425 src = ~src;
429 * Now, evaluate the flags. This stuff is based on
430 * Per Zander's CRISv10 simulator.
432 switch (env->cc_size) {
433 case 1:
434 if ((res & 0x80L) != 0L) {
435 flags |= N_FLAG;
436 if (((src & 0x80L) == 0L) && ((dst & 0x80L) == 0L)) {
437 flags |= V_FLAG;
438 } else if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) {
439 flags |= C_FLAG;
441 } else {
442 if ((res & 0xFFL) == 0L) {
443 flags |= Z_FLAG;
445 if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) {
446 flags |= V_FLAG;
448 if ((dst & 0x80L) != 0L || (src & 0x80L) != 0L) {
449 flags |= C_FLAG;
452 break;
453 case 2:
454 if ((res & 0x8000L) != 0L) {
455 flags |= N_FLAG;
456 if (((src & 0x8000L) == 0L) && ((dst & 0x8000L) == 0L)) {
457 flags |= V_FLAG;
458 } else if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) {
459 flags |= C_FLAG;
461 } else {
462 if ((res & 0xFFFFL) == 0L) {
463 flags |= Z_FLAG;
465 if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) {
466 flags |= V_FLAG;
468 if ((dst & 0x8000L) != 0L || (src & 0x8000L) != 0L) {
469 flags |= C_FLAG;
472 break;
473 case 4:
474 if ((res & 0x80000000L) != 0L) {
475 flags |= N_FLAG;
476 if (((src & 0x80000000L) == 0L) && ((dst & 0x80000000L) == 0L)) {
477 flags |= V_FLAG;
478 } else if (((src & 0x80000000L) != 0L) &&
479 ((dst & 0x80000000L) != 0L)) {
480 flags |= C_FLAG;
482 } else {
483 if (res == 0L) {
484 flags |= Z_FLAG;
486 if (((src & 0x80000000L) != 0L) && ((dst & 0x80000000L) != 0L)) {
487 flags |= V_FLAG;
489 if ((dst & 0x80000000L) != 0L || (src & 0x80000000L) != 0L) {
490 flags |= C_FLAG;
493 break;
494 default:
495 break;
498 if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) {
499 flags ^= C_FLAG;
502 env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags,
503 env->pregs[PR_CCS]);
506 void helper_top_evaluate_flags(CPUCRISState *env)
508 switch (env->cc_op) {
509 case CC_OP_MCP:
510 env->pregs[PR_CCS]
511 = helper_evaluate_flags_mcp(env, env->pregs[PR_CCS],
512 env->cc_src, env->cc_dest,
513 env->cc_result);
514 break;
515 case CC_OP_MULS:
516 env->pregs[PR_CCS]
517 = helper_evaluate_flags_muls(env, env->pregs[PR_CCS],
518 env->cc_result, env->pregs[PR_MOF]);
519 break;
520 case CC_OP_MULU:
521 env->pregs[PR_CCS]
522 = helper_evaluate_flags_mulu(env, env->pregs[PR_CCS],
523 env->cc_result, env->pregs[PR_MOF]);
524 break;
525 case CC_OP_MOVE:
526 case CC_OP_AND:
527 case CC_OP_OR:
528 case CC_OP_XOR:
529 case CC_OP_ASR:
530 case CC_OP_LSR:
531 case CC_OP_LSL:
532 switch (env->cc_size) {
533 case 4:
534 env->pregs[PR_CCS] =
535 helper_evaluate_flags_move_4(env,
536 env->pregs[PR_CCS],
537 env->cc_result);
538 break;
539 case 2:
540 env->pregs[PR_CCS] =
541 helper_evaluate_flags_move_2(env,
542 env->pregs[PR_CCS],
543 env->cc_result);
544 break;
545 default:
546 helper_evaluate_flags(env);
547 break;
549 break;
550 case CC_OP_FLAGS:
551 /* live. */
552 break;
553 case CC_OP_SUB:
554 case CC_OP_CMP:
555 if (env->cc_size == 4) {
556 env->pregs[PR_CCS] =
557 helper_evaluate_flags_sub_4(env,
558 env->pregs[PR_CCS],
559 env->cc_src, env->cc_dest,
560 env->cc_result);
561 } else {
562 helper_evaluate_flags(env);
564 break;
565 default:
566 switch (env->cc_size) {
567 case 4:
568 env->pregs[PR_CCS] =
569 helper_evaluate_flags_alu_4(env,
570 env->pregs[PR_CCS],
571 env->cc_src, env->cc_dest,
572 env->cc_result);
573 break;
574 default:
575 helper_evaluate_flags(env);
576 break;
578 break;