Correct P flag assertion in rfe.
[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         int rflag = env->pregs[PR_CCS] & R_FLAG;
206
207         D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 
208                  env->pregs[PR_ERP], env->pregs[PR_PID],
209                  env->pregs[PR_CCS],
210                  env->btarget));
211
212         cris_ccs_rshift(env);
213
214         /* RFE sets the P_FLAG only if the R_FLAG is not set.  */
215         if (!rflag)
216                 env->pregs[PR_CCS] |= P_FLAG;
217 }
218
219 void helper_store(uint32_t a0)
220 {
221         if (env->pregs[PR_CCS] & P_FLAG )
222         {
223                 cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n",
224                           env->pc, a0);
225         }
226 }
227
228 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
229                           int is_asi)
230 {
231         D(printf("%s addr=%x w=%d ex=%d asi=%d\n", 
232                 __func__, addr, is_write, is_exec, is_asi));
233 }
234
235 static void evaluate_flags_writeback(uint32_t flags)
236 {
237         int x;
238
239         /* Extended arithmetics, leave the z flag alone.  */
240         x = env->cc_x;
241         if ((x || env->cc_op == CC_OP_ADDC)
242             && flags & Z_FLAG)
243                 env->cc_mask &= ~Z_FLAG;
244
245         /* all insn clear the x-flag except setf or clrf.  */
246         env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
247         flags &= env->cc_mask;
248         env->pregs[PR_CCS] |= flags;
249 }
250
251 void helper_evaluate_flags_muls(void)
252 {
253         uint32_t src;
254         uint32_t dst;
255         uint32_t res;
256         uint32_t flags = 0;
257         int64_t tmp;
258         int32_t mof;
259         int dneg;
260
261         src = env->cc_src;
262         dst = env->cc_dest;
263         res = env->cc_result;
264
265         dneg = ((int32_t)res) < 0;
266
267         mof = env->pregs[PR_MOF];
268         tmp = mof;
269         tmp <<= 32;
270         tmp |= res;
271         if (tmp == 0)
272                 flags |= Z_FLAG;
273         else if (tmp < 0)
274                 flags |= N_FLAG;
275         if ((dneg && mof != -1)
276             || (!dneg && mof != 0))
277                 flags |= V_FLAG;
278         evaluate_flags_writeback(flags);
279 }
280
281 void  helper_evaluate_flags_mulu(void)
282 {
283         uint32_t src;
284         uint32_t dst;
285         uint32_t res;
286         uint32_t flags = 0;
287         uint64_t tmp;
288         uint32_t mof;
289
290         src = env->cc_src;
291         dst = env->cc_dest;
292         res = env->cc_result;
293
294         mof = env->pregs[PR_MOF];
295         tmp = mof;
296         tmp <<= 32;
297         tmp |= res;
298         if (tmp == 0)
299                 flags |= Z_FLAG;
300         else if (tmp >> 63)
301                 flags |= N_FLAG;
302         if (mof)
303                 flags |= V_FLAG;
304
305         evaluate_flags_writeback(flags);
306 }
307
308 void  helper_evaluate_flags_mcp(void)
309 {
310         uint32_t src;
311         uint32_t dst;
312         uint32_t res;
313         uint32_t flags = 0;
314
315         src = env->cc_src;
316         dst = env->cc_dest;
317         res = env->cc_result;
318
319         if ((res & 0x80000000L) != 0L)
320         {
321                 flags |= N_FLAG;
322                 if (((src & 0x80000000L) == 0L)
323                     && ((dst & 0x80000000L) == 0L))
324                 {
325                         flags |= V_FLAG;
326                 }
327                 else if (((src & 0x80000000L) != 0L) &&
328                          ((dst & 0x80000000L) != 0L))
329                 {
330                         flags |= R_FLAG;
331                 }
332         }
333         else
334         {
335                 if (res == 0L)
336                         flags |= Z_FLAG;
337                 if (((src & 0x80000000L) != 0L)
338                     && ((dst & 0x80000000L) != 0L))
339                         flags |= V_FLAG;
340                 if ((dst & 0x80000000L) != 0L
341                     || (src & 0x80000000L) != 0L)
342                         flags |= R_FLAG;
343         }
344
345         evaluate_flags_writeback(flags);
346 }
347
348 void  helper_evaluate_flags_alu_4(void)
349 {
350         uint32_t src;
351         uint32_t dst;
352         uint32_t res;
353         uint32_t flags = 0;
354
355         src = env->cc_src;
356         dst = env->cc_dest;
357
358         /* Reconstruct the result.  */
359         switch (env->cc_op)
360         {
361                 case CC_OP_SUB:
362                         res = dst - src;
363                         break;
364                 case CC_OP_ADD:
365                         res = dst + src;
366                         break;
367                 default:
368                         res = env->cc_result;
369                         break;
370         }
371
372         if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
373                 src = ~src;
374
375         if ((res & 0x80000000L) != 0L)
376         {
377                 flags |= N_FLAG;
378                 if (((src & 0x80000000L) == 0L)
379                     && ((dst & 0x80000000L) == 0L))
380                 {
381                         flags |= V_FLAG;
382                 }
383                 else if (((src & 0x80000000L) != 0L) &&
384                          ((dst & 0x80000000L) != 0L))
385                 {
386                         flags |= C_FLAG;
387                 }
388         }
389         else
390         {
391                 if (res == 0L)
392                         flags |= Z_FLAG;
393                 if (((src & 0x80000000L) != 0L)
394                     && ((dst & 0x80000000L) != 0L))
395                         flags |= V_FLAG;
396                 if ((dst & 0x80000000L) != 0L
397                     || (src & 0x80000000L) != 0L)
398                         flags |= C_FLAG;
399         }
400
401         if (env->cc_op == CC_OP_SUB
402             || env->cc_op == CC_OP_CMP) {
403                 flags ^= C_FLAG;
404         }
405         evaluate_flags_writeback(flags);
406 }
407
408 void  helper_evaluate_flags_move_4 (void)
409 {
410         uint32_t res;
411         uint32_t flags = 0;
412
413         res = env->cc_result;
414
415         if ((int32_t)res < 0)
416                 flags |= N_FLAG;
417         else if (res == 0L)
418                 flags |= Z_FLAG;
419
420         evaluate_flags_writeback(flags);
421 }
422 void  helper_evaluate_flags_move_2 (void)
423 {
424         uint32_t src;
425         uint32_t flags = 0;
426         uint16_t res;
427
428         src = env->cc_src;
429         res = env->cc_result;
430
431         if ((int16_t)res < 0L)
432                 flags |= N_FLAG;
433         else if (res == 0)
434                 flags |= Z_FLAG;
435
436         evaluate_flags_writeback(flags);
437 }
438
439 /* TODO: This is expensive. We could split things up and only evaluate part of
440    CCR on a need to know basis. For now, we simply re-evaluate everything.  */
441 void helper_evaluate_flags (void)
442 {
443         uint32_t src;
444         uint32_t dst;
445         uint32_t res;
446         uint32_t flags = 0;
447
448         src = env->cc_src;
449         dst = env->cc_dest;
450         res = env->cc_result;
451
452         if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
453                 src = ~src;
454
455         /* Now, evaluate the flags. This stuff is based on
456            Per Zander's CRISv10 simulator.  */
457         switch (env->cc_size)
458         {
459                 case 1:
460                         if ((res & 0x80L) != 0L)
461                         {
462                                 flags |= N_FLAG;
463                                 if (((src & 0x80L) == 0L)
464                                     && ((dst & 0x80L) == 0L))
465                                 {
466                                         flags |= V_FLAG;
467                                 }
468                                 else if (((src & 0x80L) != 0L)
469                                          && ((dst & 0x80L) != 0L))
470                                 {
471                                         flags |= C_FLAG;
472                                 }
473                         }
474                         else
475                         {
476                                 if ((res & 0xFFL) == 0L)
477                                 {
478                                         flags |= Z_FLAG;
479                                 }
480                                 if (((src & 0x80L) != 0L)
481                                     && ((dst & 0x80L) != 0L))
482                                 {
483                                         flags |= V_FLAG;
484                                 }
485                                 if ((dst & 0x80L) != 0L
486                                     || (src & 0x80L) != 0L)
487                                 {
488                                         flags |= C_FLAG;
489                                 }
490                         }
491                         break;
492                 case 2:
493                         if ((res & 0x8000L) != 0L)
494                         {
495                                 flags |= N_FLAG;
496                                 if (((src & 0x8000L) == 0L)
497                                     && ((dst & 0x8000L) == 0L))
498                                 {
499                                         flags |= V_FLAG;
500                                 }
501                                 else if (((src & 0x8000L) != 0L)
502                                          && ((dst & 0x8000L) != 0L))
503                                 {
504                                         flags |= C_FLAG;
505                                 }
506                         }
507                         else
508                         {
509                                 if ((res & 0xFFFFL) == 0L)
510                                 {
511                                         flags |= Z_FLAG;
512                                 }
513                                 if (((src & 0x8000L) != 0L)
514                                     && ((dst & 0x8000L) != 0L))
515                                 {
516                                         flags |= V_FLAG;
517                                 }
518                                 if ((dst & 0x8000L) != 0L
519                                     || (src & 0x8000L) != 0L)
520                                 {
521                                         flags |= C_FLAG;
522                                 }
523                         }
524                         break;
525                 case 4:
526                         if ((res & 0x80000000L) != 0L)
527                         {
528                                 flags |= N_FLAG;
529                                 if (((src & 0x80000000L) == 0L)
530                                     && ((dst & 0x80000000L) == 0L))
531                                 {
532                                         flags |= V_FLAG;
533                                 }
534                                 else if (((src & 0x80000000L) != 0L) &&
535                                          ((dst & 0x80000000L) != 0L))
536                                 {
537                                         flags |= C_FLAG;
538                                 }
539                         }
540                         else
541                         {
542                                 if (res == 0L)
543                                         flags |= Z_FLAG;
544                                 if (((src & 0x80000000L) != 0L)
545                                     && ((dst & 0x80000000L) != 0L))
546                                         flags |= V_FLAG;
547                                 if ((dst & 0x80000000L) != 0L
548                                     || (src & 0x80000000L) != 0L)
549                                         flags |= C_FLAG;
550                         }
551                         break;
552                 default:
553                         break;
554         }
555
556         if (env->cc_op == CC_OP_SUB
557             || env->cc_op == CC_OP_CMP) {
558                 flags ^= C_FLAG;
559         }
560         evaluate_flags_writeback(flags);
561 }
562
563 void helper_top_evaluate_flags(void)
564 {
565         switch (env->cc_op)
566         {
567                 case CC_OP_MCP:
568                         helper_evaluate_flags_mcp();
569                         break;
570                 case CC_OP_MULS:
571                         helper_evaluate_flags_muls();
572                         break;
573                 case CC_OP_MULU:
574                         helper_evaluate_flags_mulu();
575                         break;
576                 case CC_OP_MOVE:
577                 case CC_OP_AND:
578                 case CC_OP_OR:
579                 case CC_OP_XOR:
580                 case CC_OP_ASR:
581                 case CC_OP_LSR:
582                 case CC_OP_LSL:
583                         switch (env->cc_size)
584                         {
585                                 case 4:
586                                         helper_evaluate_flags_move_4();
587                                         break;
588                                 case 2:
589                                         helper_evaluate_flags_move_2();
590                                         break;
591                                 default:
592                                         helper_evaluate_flags();
593                                         break;
594                         }
595                         break;
596                 case CC_OP_FLAGS:
597                         /* live.  */
598                         break;
599                 default:
600                 {
601                         switch (env->cc_size)
602                         {
603                                 case 4:
604                                         helper_evaluate_flags_alu_4();
605                                         break;
606                                 default:
607                                         helper_evaluate_flags();
608                                         break;
609                         }
610                 }
611                 break;
612         }
613 }