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