Tizen 2.1 base
[sdk/emulator/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 "cpu.h"
22 #include "dyngen-exec.h"
23 #include "mmu.h"
24 #include "helper.h"
25 #include "host-utils.h"
26
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__)
33 #else
34 #define D(x)
35 #define D_LOG(...) do { } while (0)
36 #endif
37
38 #if !defined(CONFIG_USER_ONLY)
39 #include "softmmu_exec.h"
40
41 #define MMUSUFFIX _mmu
42
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 */
59 void tlb_fill(CPUCRISState *env1, target_ulong addr, int is_write, int mmu_idx,
60               uintptr_t retaddr)
61 {
62     TranslationBlock *tb;
63     CPUCRISState *saved_env;
64     int ret;
65
66     saved_env = env;
67     env = env1;
68
69     D_LOG("%s pc=%x tpc=%x ra=%p\n", __func__,
70           env->pc, env->debug1, (void *)retaddr);
71     ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx);
72     if (unlikely(ret)) {
73         if (retaddr) {
74             /* now we have a real cpu fault */
75             tb = tb_find_pc(retaddr);
76             if (tb) {
77                 /* the PC is inside the translated code. It means that we have
78                    a virtual CPU fault */
79                 cpu_restore_state(tb, env, retaddr);
80
81                 /* Evaluate flags after retranslation.  */
82                 helper_top_evaluate_flags();
83             }
84         }
85         cpu_loop_exit(env);
86     }
87     env = saved_env;
88 }
89
90 #endif
91
92 void helper_raise_exception(uint32_t index)
93 {
94         env->exception_index = index;
95         cpu_loop_exit(env);
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);
166                         if (tlb_v) {
167                                 tlb_flush_page(env, vaddr);
168                         }
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
202 static void cris_ccs_rshift(CPUCRISState *env)
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_V32;
252 }
253
254 uint32_t helper_lz(uint32_t t0)
255 {
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);
280         if (env->pregs[PR_VR] < 32)
281                 ccs &= ~(V_FLAG | C_FLAG);
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;
410
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         }
654 }