Fix off-by-one unwinding error.
[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
26 #define MMUSUFFIX _mmu
27
28 #define SHIFT 0
29 #include "softmmu_template.h"
30
31 #define SHIFT 1
32 #include "softmmu_template.h"
33
34 #define SHIFT 2
35 #include "softmmu_template.h"
36
37 #define SHIFT 3
38 #include "softmmu_template.h"
39
40 #define D(x)
41
42 /* Try to fill the TLB and return an exception if error. If retaddr is
43    NULL, it means that the function was called in C code (i.e. not
44    from generated code or from helper.c) */
45 /* XXX: fix it to restore all registers */
46 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
47 {
48     TranslationBlock *tb;
49     CPUState *saved_env;
50     unsigned long pc;
51     int ret;
52
53     /* XXX: hack to restore env in all cases, even if not called from
54        generated code */
55     saved_env = env;
56     env = cpu_single_env;
57
58     D(fprintf(logfile, "%s pc=%x tpc=%x ra=%x\n", __func__, 
59              env->pc, env->debug1, retaddr));
60     ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
61     if (__builtin_expect(ret, 0)) {
62         if (retaddr) {
63             /* now we have a real cpu fault */
64             pc = (unsigned long)retaddr;
65             tb = tb_find_pc(pc);
66             if (tb) {
67                 /* the PC is inside the translated code. It means that we have
68                    a virtual CPU fault */
69                 cpu_restore_state(tb, env, pc, NULL);
70             }
71         }
72         cpu_loop_exit();
73     }
74     env = saved_env;
75 }
76
77 void helper_raise_exception(uint32_t index)
78 {
79         env->exception_index = index;
80         cpu_loop_exit();
81 }
82
83 void helper_tlb_flush_pid(uint32_t pid)
84 {
85 #if !defined(CONFIG_USER_ONLY)
86         cris_mmu_flush_pid(env, pid);
87 #endif
88 }
89
90 void helper_tlb_flush(void)
91 {
92         tlb_flush(env, 1);
93 }
94
95 void helper_dump(uint32_t a0, uint32_t a1)
96 {
97         (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); 
98 }
99
100 void helper_dummy(void)
101 {
102
103 }
104
105 /* Used by the tlb decoder.  */
106 #define EXTRACT_FIELD(src, start, end) \
107             (((src) >> start) & ((1 << (end - start + 1)) - 1))
108
109 void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
110 {
111         uint32_t srs;
112         srs = env->pregs[PR_SRS];
113         srs &= 3;
114         env->sregs[srs][sreg] = env->regs[reg];
115
116 #if !defined(CONFIG_USER_ONLY)
117         if (srs == 1 || srs == 2) {
118                 if (sreg == 6) {
119                         /* Writes to tlb-hi write to mm_cause as a side 
120                            effect.  */
121                         env->sregs[SFR_RW_MM_TLB_HI] = T0;
122                         env->sregs[SFR_R_MM_CAUSE] = T0;
123                 }
124                 else if (sreg == 5) {
125                         uint32_t set;
126                         uint32_t idx;
127                         uint32_t lo, hi;
128                         uint32_t vaddr;
129                         int tlb_v;
130
131                         idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
132                         set >>= 4;
133                         set &= 3;
134
135                         idx &= 15;
136                         /* We've just made a write to tlb_lo.  */
137                         lo = env->sregs[SFR_RW_MM_TLB_LO];
138                         /* Writes are done via r_mm_cause.  */
139                         hi = env->sregs[SFR_R_MM_CAUSE];
140
141                         vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi,
142                                               13, 31);
143                         vaddr <<= TARGET_PAGE_BITS;
144                         tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo,
145                                             3, 3);
146                         env->tlbsets[srs - 1][set][idx].lo = lo;
147                         env->tlbsets[srs - 1][set][idx].hi = hi;
148
149                         D(fprintf(logfile, 
150                                   "tlb flush vaddr=%x v=%d pc=%x\n", 
151                                   vaddr, tlb_v, env->pc));
152                         tlb_flush_page(env, vaddr);
153                 }
154         }
155 #endif
156 }
157
158 void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg)
159 {
160         uint32_t srs;
161         env->pregs[PR_SRS] &= 3;
162         srs = env->pregs[PR_SRS];
163         
164 #if !defined(CONFIG_USER_ONLY)
165         if (srs == 1 || srs == 2)
166         {
167                 uint32_t set;
168                 uint32_t idx;
169                 uint32_t lo, hi;
170
171                 idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
172                 set >>= 4;
173                 set &= 3;
174                 idx &= 15;
175
176                 /* Update the mirror regs.  */
177                 hi = env->tlbsets[srs - 1][set][idx].hi;
178                 lo = env->tlbsets[srs - 1][set][idx].lo;
179                 env->sregs[SFR_RW_MM_TLB_HI] = hi;
180                 env->sregs[SFR_RW_MM_TLB_LO] = lo;
181         }
182 #endif
183         env->regs[reg] = env->sregs[srs][sreg];
184         RETURN();
185 }
186
187 static void cris_ccs_rshift(CPUState *env)
188 {
189         uint32_t ccs;
190
191         /* Apply the ccs shift.  */
192         ccs = env->pregs[PR_CCS];
193         ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
194         if (ccs & U_FLAG)
195         {
196                 /* Enter user mode.  */
197                 env->ksp = env->regs[R_SP];
198                 env->regs[R_SP] = env->pregs[PR_USP];
199         }
200
201         env->pregs[PR_CCS] = ccs;
202 }
203
204 void helper_rfe(void)
205 {
206         D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 
207                  env->pregs[PR_ERP], env->pregs[PR_PID],
208                  env->pregs[PR_CCS],
209                  env->btarget));
210
211         cris_ccs_rshift(env);
212
213         /* RFE sets the P_FLAG only if the R_FLAG is not set.  */
214         if (!(env->pregs[PR_CCS] & R_FLAG))
215                 env->pregs[PR_CCS] |= P_FLAG;
216 }
217
218 void helper_store(uint32_t a0)
219 {
220         if (env->pregs[PR_CCS] & P_FLAG )
221         {
222                 cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n",
223                           env->pc, a0);
224         }
225 }
226
227 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
228                           int is_asi)
229 {
230         D(printf("%s addr=%x w=%d ex=%d asi=%d\n", 
231                 __func__, addr, is_write, is_exec, is_asi));
232 }
233
234 static void evaluate_flags_writeback(uint32_t flags)
235 {
236         int x;
237
238         /* Extended arithmetics, leave the z flag alone.  */
239         env->debug3 = env->pregs[PR_CCS];
240
241         if (env->cc_x_live)
242                 x = env->cc_x;
243         else
244                 x = env->pregs[PR_CCS] & X_FLAG;
245
246         if ((x || env->cc_op == CC_OP_ADDC)
247             && flags & Z_FLAG)
248                 env->cc_mask &= ~Z_FLAG;
249
250         /* all insn clear the x-flag except setf or clrf.  */
251         env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
252         flags &= env->cc_mask;
253         env->pregs[PR_CCS] |= flags;
254 }
255
256 void helper_evaluate_flags_muls(void)
257 {
258         uint32_t src;
259         uint32_t dst;
260         uint32_t res;
261         uint32_t flags = 0;
262         int64_t tmp;
263         int32_t mof;
264         int dneg;
265
266         src = env->cc_src;
267         dst = env->cc_dest;
268         res = env->cc_result;
269
270         dneg = ((int32_t)res) < 0;
271
272         mof = env->pregs[PR_MOF];
273         tmp = mof;
274         tmp <<= 32;
275         tmp |= res;
276         if (tmp == 0)
277                 flags |= Z_FLAG;
278         else if (tmp < 0)
279                 flags |= N_FLAG;
280         if ((dneg && mof != -1)
281             || (!dneg && mof != 0))
282                 flags |= V_FLAG;
283         evaluate_flags_writeback(flags);
284 }
285
286 void  helper_evaluate_flags_mulu(void)
287 {
288         uint32_t src;
289         uint32_t dst;
290         uint32_t res;
291         uint32_t flags = 0;
292         uint64_t tmp;
293         uint32_t mof;
294
295         src = env->cc_src;
296         dst = env->cc_dest;
297         res = env->cc_result;
298
299         mof = env->pregs[PR_MOF];
300         tmp = mof;
301         tmp <<= 32;
302         tmp |= res;
303         if (tmp == 0)
304                 flags |= Z_FLAG;
305         else if (tmp >> 63)
306                 flags |= N_FLAG;
307         if (mof)
308                 flags |= V_FLAG;
309
310         evaluate_flags_writeback(flags);
311 }
312
313 void  helper_evaluate_flags_mcp(void)
314 {
315         uint32_t src;
316         uint32_t dst;
317         uint32_t res;
318         uint32_t flags = 0;
319
320         src = env->cc_src;
321         dst = env->cc_dest;
322         res = env->cc_result;
323
324         if ((res & 0x80000000L) != 0L)
325         {
326                 flags |= N_FLAG;
327                 if (((src & 0x80000000L) == 0L)
328                     && ((dst & 0x80000000L) == 0L))
329                 {
330                         flags |= V_FLAG;
331                 }
332                 else if (((src & 0x80000000L) != 0L) &&
333                          ((dst & 0x80000000L) != 0L))
334                 {
335                         flags |= R_FLAG;
336                 }
337         }
338         else
339         {
340                 if (res == 0L)
341                         flags |= Z_FLAG;
342                 if (((src & 0x80000000L) != 0L)
343                     && ((dst & 0x80000000L) != 0L))
344                         flags |= V_FLAG;
345                 if ((dst & 0x80000000L) != 0L
346                     || (src & 0x80000000L) != 0L)
347                         flags |= R_FLAG;
348         }
349
350         evaluate_flags_writeback(flags);
351 }
352
353 void  helper_evaluate_flags_alu_4(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;
361         dst = env->cc_dest;
362         res = env->cc_result;
363
364         if ((res & 0x80000000L) != 0L)
365         {
366                 flags |= N_FLAG;
367                 if (((src & 0x80000000L) == 0L)
368                     && ((dst & 0x80000000L) == 0L))
369                 {
370                         flags |= V_FLAG;
371                 }
372                 else if (((src & 0x80000000L) != 0L) &&
373                          ((dst & 0x80000000L) != 0L))
374                 {
375                         flags |= C_FLAG;
376                 }
377         }
378         else
379         {
380                 if (res == 0L)
381                         flags |= Z_FLAG;
382                 if (((src & 0x80000000L) != 0L)
383                     && ((dst & 0x80000000L) != 0L))
384                         flags |= V_FLAG;
385                 if ((dst & 0x80000000L) != 0L
386                     || (src & 0x80000000L) != 0L)
387                         flags |= C_FLAG;
388         }
389
390         if (env->cc_op == CC_OP_SUB
391             || env->cc_op == CC_OP_CMP) {
392                 flags ^= C_FLAG;
393         }
394         evaluate_flags_writeback(flags);
395 }
396
397 void  helper_evaluate_flags_move_4 (void)
398 {
399         uint32_t src;
400         uint32_t res;
401         uint32_t flags = 0;
402
403         src = env->cc_src;
404         res = env->cc_result;
405
406         if ((int32_t)res < 0)
407                 flags |= N_FLAG;
408         else if (res == 0L)
409                 flags |= Z_FLAG;
410
411         evaluate_flags_writeback(flags);
412 }
413 void  helper_evaluate_flags_move_2 (void)
414 {
415         uint32_t src;
416         uint32_t flags = 0;
417         uint16_t res;
418
419         src = env->cc_src;
420         res = env->cc_result;
421
422         if ((int16_t)res < 0L)
423                 flags |= N_FLAG;
424         else if (res == 0)
425                 flags |= Z_FLAG;
426
427         evaluate_flags_writeback(flags);
428 }
429
430 /* TODO: This is expensive. We could split things up and only evaluate part of
431    CCR on a need to know basis. For now, we simply re-evaluate everything.  */
432 void helper_evaluate_flags (void)
433 {
434         uint32_t src;
435         uint32_t dst;
436         uint32_t res;
437         uint32_t flags = 0;
438
439         src = env->cc_src;
440         dst = env->cc_dest;
441         res = env->cc_result;
442
443
444         /* Now, evaluate the flags. This stuff is based on
445            Per Zander's CRISv10 simulator.  */
446         switch (env->cc_size)
447         {
448                 case 1:
449                         if ((res & 0x80L) != 0L)
450                         {
451                                 flags |= N_FLAG;
452                                 if (((src & 0x80L) == 0L)
453                                     && ((dst & 0x80L) == 0L))
454                                 {
455                                         flags |= V_FLAG;
456                                 }
457                                 else if (((src & 0x80L) != 0L)
458                                          && ((dst & 0x80L) != 0L))
459                                 {
460                                         flags |= C_FLAG;
461                                 }
462                         }
463                         else
464                         {
465                                 if ((res & 0xFFL) == 0L)
466                                 {
467                                         flags |= Z_FLAG;
468                                 }
469                                 if (((src & 0x80L) != 0L)
470                                     && ((dst & 0x80L) != 0L))
471                                 {
472                                         flags |= V_FLAG;
473                                 }
474                                 if ((dst & 0x80L) != 0L
475                                     || (src & 0x80L) != 0L)
476                                 {
477                                         flags |= C_FLAG;
478                                 }
479                         }
480                         break;
481                 case 2:
482                         if ((res & 0x8000L) != 0L)
483                         {
484                                 flags |= N_FLAG;
485                                 if (((src & 0x8000L) == 0L)
486                                     && ((dst & 0x8000L) == 0L))
487                                 {
488                                         flags |= V_FLAG;
489                                 }
490                                 else if (((src & 0x8000L) != 0L)
491                                          && ((dst & 0x8000L) != 0L))
492                                 {
493                                         flags |= C_FLAG;
494                                 }
495                         }
496                         else
497                         {
498                                 if ((res & 0xFFFFL) == 0L)
499                                 {
500                                         flags |= Z_FLAG;
501                                 }
502                                 if (((src & 0x8000L) != 0L)
503                                     && ((dst & 0x8000L) != 0L))
504                                 {
505                                         flags |= V_FLAG;
506                                 }
507                                 if ((dst & 0x8000L) != 0L
508                                     || (src & 0x8000L) != 0L)
509                                 {
510                                         flags |= C_FLAG;
511                                 }
512                         }
513                         break;
514                 case 4:
515                         if ((res & 0x80000000L) != 0L)
516                         {
517                                 flags |= N_FLAG;
518                                 if (((src & 0x80000000L) == 0L)
519                                     && ((dst & 0x80000000L) == 0L))
520                                 {
521                                         flags |= V_FLAG;
522                                 }
523                                 else if (((src & 0x80000000L) != 0L) &&
524                                          ((dst & 0x80000000L) != 0L))
525                                 {
526                                         flags |= C_FLAG;
527                                 }
528                         }
529                         else
530                         {
531                                 if (res == 0L)
532                                         flags |= Z_FLAG;
533                                 if (((src & 0x80000000L) != 0L)
534                                     && ((dst & 0x80000000L) != 0L))
535                                         flags |= V_FLAG;
536                                 if ((dst & 0x80000000L) != 0L
537                                     || (src & 0x80000000L) != 0L)
538                                         flags |= C_FLAG;
539                         }
540                         break;
541                 default:
542                         break;
543         }
544
545         if (env->cc_op == CC_OP_SUB
546             || env->cc_op == CC_OP_CMP) {
547                 flags ^= C_FLAG;
548         }
549         evaluate_flags_writeback(flags);
550 }