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