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