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