CRIS: Restructure the translator to allow for better code generation.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <assert.h>
23 #include "exec.h"
24 #include "mmu.h"
25 #include "helper.h"
26
27 #define MMUSUFFIX _mmu
28
29 #define SHIFT 0
30 #include "softmmu_template.h"
31
32 #define SHIFT 1
33 #include "softmmu_template.h"
34
35 #define SHIFT 2
36 #include "softmmu_template.h"
37
38 #define SHIFT 3
39 #include "softmmu_template.h"
40
41 #define D(x)
42
43 /* Try to fill the TLB and return an exception if error. If retaddr is
44    NULL, it means that the function was called in C code (i.e. not
45    from generated code or from helper.c) */
46 /* XXX: fix it to restore all registers */
47 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
48 {
49     TranslationBlock *tb;
50     CPUState *saved_env;
51     unsigned long pc;
52     int ret;
53
54     /* XXX: hack to restore env in all cases, even if not called from
55        generated code */
56     saved_env = env;
57     env = cpu_single_env;
58
59     D(fprintf(logfile, "%s pc=%x tpc=%x ra=%x\n", __func__, 
60              env->pc, env->debug1, retaddr));
61     ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
62     if (__builtin_expect(ret, 0)) {
63         if (retaddr) {
64             /* now we have a real cpu fault */
65             pc = (unsigned long)retaddr;
66             tb = tb_find_pc(pc);
67             if (tb) {
68                 /* the PC is inside the translated code. It means that we have
69                    a virtual CPU fault */
70                 cpu_restore_state(tb, env, pc, NULL);
71
72                 /* Evaluate flags after retranslation.  */
73                 helper_top_evaluate_flags();
74             }
75         }
76         cpu_loop_exit();
77     }
78     env = saved_env;
79 }
80
81 void helper_raise_exception(uint32_t index)
82 {
83         env->exception_index = index;
84         cpu_loop_exit();
85 }
86
87 void helper_tlb_flush_pid(uint32_t pid)
88 {
89 #if !defined(CONFIG_USER_ONLY)
90         cris_mmu_flush_pid(env, pid);
91 #endif
92 }
93
94 void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2)
95 {
96         (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); 
97 }
98
99 void helper_dummy(void)
100 {
101
102 }
103
104 /* Used by the tlb decoder.  */
105 #define EXTRACT_FIELD(src, start, end) \
106             (((src) >> start) & ((1 << (end - start + 1)) - 1))
107
108 void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
109 {
110         uint32_t srs;
111         srs = env->pregs[PR_SRS];
112         srs &= 3;
113         env->sregs[srs][sreg] = env->regs[reg];
114
115 #if !defined(CONFIG_USER_ONLY)
116         if (srs == 1 || srs == 2) {
117                 if (sreg == 6) {
118                         /* Writes to tlb-hi write to mm_cause as a side 
119                            effect.  */
120                         env->sregs[SFR_RW_MM_TLB_HI] = T0;
121                         env->sregs[SFR_R_MM_CAUSE] = T0;
122                 }
123                 else if (sreg == 5) {
124                         uint32_t set;
125                         uint32_t idx;
126                         uint32_t lo, hi;
127                         uint32_t vaddr;
128                         int tlb_v;
129
130                         idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
131                         set >>= 4;
132                         set &= 3;
133
134                         idx &= 15;
135                         /* We've just made a write to tlb_lo.  */
136                         lo = env->sregs[SFR_RW_MM_TLB_LO];
137                         /* Writes are done via r_mm_cause.  */
138                         hi = env->sregs[SFR_R_MM_CAUSE];
139
140                         vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi,
141                                               13, 31);
142                         vaddr <<= TARGET_PAGE_BITS;
143                         tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo,
144                                             3, 3);
145                         env->tlbsets[srs - 1][set][idx].lo = lo;
146                         env->tlbsets[srs - 1][set][idx].hi = hi;
147
148                         D(fprintf(logfile, 
149                                   "tlb flush vaddr=%x v=%d pc=%x\n", 
150                                   vaddr, tlb_v, env->pc));
151                         tlb_flush_page(env, vaddr);
152                 }
153         }
154 #endif
155 }
156
157 void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg)
158 {
159         uint32_t srs;
160         env->pregs[PR_SRS] &= 3;
161         srs = env->pregs[PR_SRS];
162         
163 #if !defined(CONFIG_USER_ONLY)
164         if (srs == 1 || srs == 2)
165         {
166                 uint32_t set;
167                 uint32_t idx;
168                 uint32_t lo, hi;
169
170                 idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
171                 set >>= 4;
172                 set &= 3;
173                 idx &= 15;
174
175                 /* Update the mirror regs.  */
176                 hi = env->tlbsets[srs - 1][set][idx].hi;
177                 lo = env->tlbsets[srs - 1][set][idx].lo;
178                 env->sregs[SFR_RW_MM_TLB_HI] = hi;
179                 env->sregs[SFR_RW_MM_TLB_LO] = lo;
180         }
181 #endif
182         env->regs[reg] = env->sregs[srs][sreg];
183         RETURN();
184 }
185
186 static void cris_ccs_rshift(CPUState *env)
187 {
188         uint32_t ccs;
189
190         /* Apply the ccs shift.  */
191         ccs = env->pregs[PR_CCS];
192         ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
193         if (ccs & U_FLAG)
194         {
195                 /* Enter user mode.  */
196                 env->ksp = env->regs[R_SP];
197                 env->regs[R_SP] = env->pregs[PR_USP];
198         }
199
200         env->pregs[PR_CCS] = ccs;
201 }
202
203 void helper_rfe(void)
204 {
205         D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 
206                  env->pregs[PR_ERP], env->pregs[PR_PID],
207                  env->pregs[PR_CCS],
208                  env->btarget));
209
210         cris_ccs_rshift(env);
211
212         /* RFE sets the P_FLAG only if the R_FLAG is not set.  */
213         if (!(env->pregs[PR_CCS] & R_FLAG))
214                 env->pregs[PR_CCS] |= P_FLAG;
215 }
216
217 void helper_store(uint32_t a0)
218 {
219         if (env->pregs[PR_CCS] & P_FLAG )
220         {
221                 cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n",
222                           env->pc, a0);
223         }
224 }
225
226 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
227                           int is_asi)
228 {
229         D(printf("%s addr=%x w=%d ex=%d asi=%d\n", 
230                 __func__, addr, is_write, is_exec, is_asi));
231 }
232
233 static void evaluate_flags_writeback(uint32_t flags)
234 {
235         int x;
236
237         /* Extended arithmetics, leave the z flag alone.  */
238         x = env->cc_x;
239         if ((x || env->cc_op == CC_OP_ADDC)
240             && flags & Z_FLAG)
241                 env->cc_mask &= ~Z_FLAG;
242
243         /* all insn clear the x-flag except setf or clrf.  */
244         env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
245         flags &= env->cc_mask;
246         env->pregs[PR_CCS] |= flags;
247 }
248
249 void helper_evaluate_flags_muls(void)
250 {
251         uint32_t src;
252         uint32_t dst;
253         uint32_t res;
254         uint32_t flags = 0;
255         int64_t tmp;
256         int32_t mof;
257         int dneg;
258
259         src = env->cc_src;
260         dst = env->cc_dest;
261         res = env->cc_result;
262
263         dneg = ((int32_t)res) < 0;
264
265         mof = env->pregs[PR_MOF];
266         tmp = mof;
267         tmp <<= 32;
268         tmp |= res;
269         if (tmp == 0)
270                 flags |= Z_FLAG;
271         else if (tmp < 0)
272                 flags |= N_FLAG;
273         if ((dneg && mof != -1)
274             || (!dneg && mof != 0))
275                 flags |= V_FLAG;
276         evaluate_flags_writeback(flags);
277 }
278
279 void  helper_evaluate_flags_mulu(void)
280 {
281         uint32_t src;
282         uint32_t dst;
283         uint32_t res;
284         uint32_t flags = 0;
285         uint64_t tmp;
286         uint32_t mof;
287
288         src = env->cc_src;
289         dst = env->cc_dest;
290         res = env->cc_result;
291
292         mof = env->pregs[PR_MOF];
293         tmp = mof;
294         tmp <<= 32;
295         tmp |= res;
296         if (tmp == 0)
297                 flags |= Z_FLAG;
298         else if (tmp >> 63)
299                 flags |= N_FLAG;
300         if (mof)
301                 flags |= V_FLAG;
302
303         evaluate_flags_writeback(flags);
304 }
305
306 void  helper_evaluate_flags_mcp(void)
307 {
308         uint32_t src;
309         uint32_t dst;
310         uint32_t res;
311         uint32_t flags = 0;
312
313         src = env->cc_src;
314         dst = env->cc_dest;
315         res = env->cc_result;
316
317         if ((res & 0x80000000L) != 0L)
318         {
319                 flags |= N_FLAG;
320                 if (((src & 0x80000000L) == 0L)
321                     && ((dst & 0x80000000L) == 0L))
322                 {
323                         flags |= V_FLAG;
324                 }
325                 else if (((src & 0x80000000L) != 0L) &&
326                          ((dst & 0x80000000L) != 0L))
327                 {
328                         flags |= R_FLAG;
329                 }
330         }
331         else
332         {
333                 if (res == 0L)
334                         flags |= Z_FLAG;
335                 if (((src & 0x80000000L) != 0L)
336                     && ((dst & 0x80000000L) != 0L))
337                         flags |= V_FLAG;
338                 if ((dst & 0x80000000L) != 0L
339                     || (src & 0x80000000L) != 0L)
340                         flags |= R_FLAG;
341         }
342
343         evaluate_flags_writeback(flags);
344 }
345
346 void  helper_evaluate_flags_alu_4(void)
347 {
348         uint32_t src;
349         uint32_t dst;
350         uint32_t res;
351         uint32_t flags = 0;
352
353         src = env->cc_src;
354         dst = env->cc_dest;
355
356         /* Reconstruct the result.  */
357         switch (env->cc_op)
358         {
359                 case CC_OP_SUB:
360                         res = dst - src;
361                         break;
362                 case CC_OP_ADD:
363                         res = dst + src;
364                         break;
365                 default:
366                         res = env->cc_result;
367                         break;
368         }
369
370         if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
371                 src = ~src;
372
373         if ((res & 0x80000000L) != 0L)
374         {
375                 flags |= N_FLAG;
376                 if (((src & 0x80000000L) == 0L)
377                     && ((dst & 0x80000000L) == 0L))
378                 {
379                         flags |= V_FLAG;
380                 }
381                 else if (((src & 0x80000000L) != 0L) &&
382                          ((dst & 0x80000000L) != 0L))
383                 {
384                         flags |= C_FLAG;
385                 }
386         }
387         else
388         {
389                 if (res == 0L)
390                         flags |= Z_FLAG;
391                 if (((src & 0x80000000L) != 0L)
392                     && ((dst & 0x80000000L) != 0L))
393                         flags |= V_FLAG;
394                 if ((dst & 0x80000000L) != 0L
395                     || (src & 0x80000000L) != 0L)
396                         flags |= C_FLAG;
397         }
398
399         if (env->cc_op == CC_OP_SUB
400             || env->cc_op == CC_OP_CMP) {
401                 flags ^= C_FLAG;
402         }
403         evaluate_flags_writeback(flags);
404 }
405
406 void  helper_evaluate_flags_move_4 (void)
407 {
408         uint32_t res;
409         uint32_t flags = 0;
410
411         res = env->cc_result;
412
413         if ((int32_t)res < 0)
414                 flags |= N_FLAG;
415         else if (res == 0L)
416                 flags |= Z_FLAG;
417
418         evaluate_flags_writeback(flags);
419 }
420 void  helper_evaluate_flags_move_2 (void)
421 {
422         uint32_t src;
423         uint32_t flags = 0;
424         uint16_t res;
425
426         src = env->cc_src;
427         res = env->cc_result;
428
429         if ((int16_t)res < 0L)
430                 flags |= N_FLAG;
431         else if (res == 0)
432                 flags |= Z_FLAG;
433
434         evaluate_flags_writeback(flags);
435 }
436
437 /* TODO: This is expensive. We could split things up and only evaluate part of
438    CCR on a need to know basis. For now, we simply re-evaluate everything.  */
439 void helper_evaluate_flags (void)
440 {
441         uint32_t src;
442         uint32_t dst;
443         uint32_t 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
555             || env->cc_op == CC_OP_CMP) {
556                 flags ^= C_FLAG;
557         }
558         evaluate_flags_writeback(flags);
559 }
560
561 void helper_top_evaluate_flags(void)
562 {
563         switch (env->cc_op)
564         {
565                 case CC_OP_MCP:
566                         helper_evaluate_flags_mcp();
567                         break;
568                 case CC_OP_MULS:
569                         helper_evaluate_flags_muls();
570                         break;
571                 case CC_OP_MULU:
572                         helper_evaluate_flags_mulu();
573                         break;
574                 case CC_OP_MOVE:
575                 case CC_OP_AND:
576                 case CC_OP_OR:
577                 case CC_OP_XOR:
578                 case CC_OP_ASR:
579                 case CC_OP_LSR:
580                 case CC_OP_LSL:
581                         switch (env->cc_size)
582                         {
583                                 case 4:
584                                         helper_evaluate_flags_move_4();
585                                         break;
586                                 case 2:
587                                         helper_evaluate_flags_move_2();
588                                         break;
589                                 default:
590                                         helper_evaluate_flags();
591                                         break;
592                         }
593                         break;
594                 case CC_OP_FLAGS:
595                         /* live.  */
596                         break;
597                 default:
598                 {
599                         switch (env->cc_size)
600                         {
601                                 case 4:
602                                         helper_evaluate_flags_alu_4();
603                                         break;
604                                 default:
605                                         helper_evaluate_flags();
606                                         break;
607                         }
608                 }
609                 break;
610         }
611 }