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