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