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