Show size for unassigned accesses (Robert Reif)
[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 D(x)
28
29 #if !defined(CONFIG_USER_ONLY)
30
31 #define MMUSUFFIX _mmu
32
33 #define SHIFT 0
34 #include "softmmu_template.h"
35
36 #define SHIFT 1
37 #include "softmmu_template.h"
38
39 #define SHIFT 2
40 #include "softmmu_template.h"
41
42 #define SHIFT 3
43 #include "softmmu_template.h"
44
45 /* Try to fill the TLB and return an exception if error. If retaddr is
46    NULL, it means that the function was called in C code (i.e. not
47    from generated code or from helper.c) */
48 /* XXX: fix it to restore all registers */
49 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
50 {
51     TranslationBlock *tb;
52     CPUState *saved_env;
53     unsigned long pc;
54     int ret;
55
56     /* XXX: hack to restore env in all cases, even if not called from
57        generated code */
58     saved_env = env;
59     env = cpu_single_env;
60
61     D(fprintf(logfile, "%s pc=%x tpc=%x ra=%x\n", __func__, 
62              env->pc, env->debug1, retaddr));
63     ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
64     if (unlikely(ret)) {
65         if (retaddr) {
66             /* now we have a real cpu fault */
67             pc = (unsigned long)retaddr;
68             tb = tb_find_pc(pc);
69             if (tb) {
70                 /* the PC is inside the translated code. It means that we have
71                    a virtual CPU fault */
72                 cpu_restore_state(tb, env, pc, NULL);
73
74                 /* Evaluate flags after retranslation.  */
75                 helper_top_evaluate_flags();
76             }
77         }
78         cpu_loop_exit();
79     }
80     env = saved_env;
81 }
82
83 #endif
84
85 void helper_raise_exception(uint32_t index)
86 {
87         env->exception_index = index;
88         cpu_loop_exit();
89 }
90
91 void helper_tlb_flush_pid(uint32_t pid)
92 {
93 #if !defined(CONFIG_USER_ONLY)
94         pid &= 0xff;
95         if (pid != (env->pregs[PR_PID] & 0xff))
96                 cris_mmu_flush_pid(env, env->pregs[PR_PID]);
97 #endif
98 }
99
100 void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2)
101 {
102         (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); 
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] = env->regs[reg];
122                         env->sregs[SFR_R_MM_CAUSE] = env->regs[reg];
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         int rflag = env->pregs[PR_CCS] & R_FLAG;
207
208         D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 
209                  env->pregs[PR_ERP], env->pregs[PR_PID],
210                  env->pregs[PR_CCS],
211                  env->btarget));
212
213         cris_ccs_rshift(env);
214
215         /* RFE sets the P_FLAG only if the R_FLAG is not set.  */
216         if (!rflag)
217                 env->pregs[PR_CCS] |= P_FLAG;
218 }
219
220 void helper_rfn(void)
221 {
222         int rflag = env->pregs[PR_CCS] & R_FLAG;
223
224         D(fprintf(logfile, "rfn: 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         /* Set the P_FLAG only if the R_FLAG is not set.  */
232         if (!rflag)
233                 env->pregs[PR_CCS] |= P_FLAG;
234
235     /* Always set the M flag.  */
236     env->pregs[PR_CCS] |= M_FLAG;
237 }
238
239 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
240                           int is_asi, int size)
241 {
242         D(printf("%s addr=%x w=%d ex=%d asi=%d, size=%d\n",
243                 __func__, addr, is_write, is_exec, is_asi, size));
244 }
245
246 static void evaluate_flags_writeback(uint32_t flags)
247 {
248         int x;
249
250         /* Extended arithmetics, leave the z flag alone.  */
251         x = env->cc_x;
252         if ((x || env->cc_op == CC_OP_ADDC)
253             && flags & Z_FLAG)
254                 env->cc_mask &= ~Z_FLAG;
255
256         /* all insn clear the x-flag except setf or clrf.  */
257         env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
258         flags &= env->cc_mask;
259         env->pregs[PR_CCS] |= flags;
260 }
261
262 void helper_evaluate_flags_muls(void)
263 {
264         uint32_t src;
265         uint32_t dst;
266         uint32_t res;
267         uint32_t flags = 0;
268         int64_t tmp;
269         int32_t mof;
270         int dneg;
271
272         src = env->cc_src;
273         dst = env->cc_dest;
274         res = env->cc_result;
275
276         dneg = ((int32_t)res) < 0;
277
278         mof = env->pregs[PR_MOF];
279         tmp = mof;
280         tmp <<= 32;
281         tmp |= res;
282         if (tmp == 0)
283                 flags |= Z_FLAG;
284         else if (tmp < 0)
285                 flags |= N_FLAG;
286         if ((dneg && mof != -1)
287             || (!dneg && mof != 0))
288                 flags |= V_FLAG;
289         evaluate_flags_writeback(flags);
290 }
291
292 void  helper_evaluate_flags_mulu(void)
293 {
294         uint32_t src;
295         uint32_t dst;
296         uint32_t res;
297         uint32_t flags = 0;
298         uint64_t tmp;
299         uint32_t mof;
300
301         src = env->cc_src;
302         dst = env->cc_dest;
303         res = env->cc_result;
304
305         mof = env->pregs[PR_MOF];
306         tmp = mof;
307         tmp <<= 32;
308         tmp |= res;
309         if (tmp == 0)
310                 flags |= Z_FLAG;
311         else if (tmp >> 63)
312                 flags |= N_FLAG;
313         if (mof)
314                 flags |= V_FLAG;
315
316         evaluate_flags_writeback(flags);
317 }
318
319 void  helper_evaluate_flags_mcp(void)
320 {
321         uint32_t src;
322         uint32_t dst;
323         uint32_t res;
324         uint32_t flags = 0;
325
326         src = env->cc_src;
327         dst = env->cc_dest;
328         res = env->cc_result;
329
330         if ((res & 0x80000000L) != 0L)
331         {
332                 flags |= N_FLAG;
333                 if (((src & 0x80000000L) == 0L)
334                     && ((dst & 0x80000000L) == 0L))
335                 {
336                         flags |= V_FLAG;
337                 }
338                 else if (((src & 0x80000000L) != 0L) &&
339                          ((dst & 0x80000000L) != 0L))
340                 {
341                         flags |= R_FLAG;
342                 }
343         }
344         else
345         {
346                 if (res == 0L)
347                         flags |= Z_FLAG;
348                 if (((src & 0x80000000L) != 0L)
349                     && ((dst & 0x80000000L) != 0L))
350                         flags |= V_FLAG;
351                 if ((dst & 0x80000000L) != 0L
352                     || (src & 0x80000000L) != 0L)
353                         flags |= R_FLAG;
354         }
355
356         evaluate_flags_writeback(flags);
357 }
358
359 void  helper_evaluate_flags_alu_4(void)
360 {
361         uint32_t src;
362         uint32_t dst;
363         uint32_t res;
364         uint32_t flags = 0;
365
366         src = env->cc_src;
367         dst = env->cc_dest;
368
369         /* Reconstruct the result.  */
370         switch (env->cc_op)
371         {
372                 case CC_OP_SUB:
373                         res = dst - src;
374                         break;
375                 case CC_OP_ADD:
376                         res = dst + src;
377                         break;
378                 default:
379                         res = env->cc_result;
380                         break;
381         }
382
383         if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
384                 src = ~src;
385
386         if ((res & 0x80000000L) != 0L)
387         {
388                 flags |= N_FLAG;
389                 if (((src & 0x80000000L) == 0L)
390                     && ((dst & 0x80000000L) == 0L))
391                 {
392                         flags |= V_FLAG;
393                 }
394                 else if (((src & 0x80000000L) != 0L) &&
395                          ((dst & 0x80000000L) != 0L))
396                 {
397                         flags |= C_FLAG;
398                 }
399         }
400         else
401         {
402                 if (res == 0L)
403                         flags |= Z_FLAG;
404                 if (((src & 0x80000000L) != 0L)
405                     && ((dst & 0x80000000L) != 0L))
406                         flags |= V_FLAG;
407                 if ((dst & 0x80000000L) != 0L
408                     || (src & 0x80000000L) != 0L)
409                         flags |= C_FLAG;
410         }
411
412         if (env->cc_op == CC_OP_SUB
413             || env->cc_op == CC_OP_CMP) {
414                 flags ^= C_FLAG;
415         }
416         evaluate_flags_writeback(flags);
417 }
418
419 void  helper_evaluate_flags_move_4 (void)
420 {
421         uint32_t res;
422         uint32_t flags = 0;
423
424         res = env->cc_result;
425
426         if ((int32_t)res < 0)
427                 flags |= N_FLAG;
428         else if (res == 0L)
429                 flags |= Z_FLAG;
430
431         evaluate_flags_writeback(flags);
432 }
433 void  helper_evaluate_flags_move_2 (void)
434 {
435         uint32_t src;
436         uint32_t flags = 0;
437         uint16_t res;
438
439         src = env->cc_src;
440         res = env->cc_result;
441
442         if ((int16_t)res < 0L)
443                 flags |= N_FLAG;
444         else if (res == 0)
445                 flags |= Z_FLAG;
446
447         evaluate_flags_writeback(flags);
448 }
449
450 /* TODO: This is expensive. We could split things up and only evaluate part of
451    CCR on a need to know basis. For now, we simply re-evaluate everything.  */
452 void helper_evaluate_flags (void)
453 {
454         uint32_t src;
455         uint32_t dst;
456         uint32_t res;
457         uint32_t flags = 0;
458
459         src = env->cc_src;
460         dst = env->cc_dest;
461         res = env->cc_result;
462
463         if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
464                 src = ~src;
465
466         /* Now, evaluate the flags. This stuff is based on
467            Per Zander's CRISv10 simulator.  */
468         switch (env->cc_size)
469         {
470                 case 1:
471                         if ((res & 0x80L) != 0L)
472                         {
473                                 flags |= N_FLAG;
474                                 if (((src & 0x80L) == 0L)
475                                     && ((dst & 0x80L) == 0L))
476                                 {
477                                         flags |= V_FLAG;
478                                 }
479                                 else if (((src & 0x80L) != 0L)
480                                          && ((dst & 0x80L) != 0L))
481                                 {
482                                         flags |= C_FLAG;
483                                 }
484                         }
485                         else
486                         {
487                                 if ((res & 0xFFL) == 0L)
488                                 {
489                                         flags |= Z_FLAG;
490                                 }
491                                 if (((src & 0x80L) != 0L)
492                                     && ((dst & 0x80L) != 0L))
493                                 {
494                                         flags |= V_FLAG;
495                                 }
496                                 if ((dst & 0x80L) != 0L
497                                     || (src & 0x80L) != 0L)
498                                 {
499                                         flags |= C_FLAG;
500                                 }
501                         }
502                         break;
503                 case 2:
504                         if ((res & 0x8000L) != 0L)
505                         {
506                                 flags |= N_FLAG;
507                                 if (((src & 0x8000L) == 0L)
508                                     && ((dst & 0x8000L) == 0L))
509                                 {
510                                         flags |= V_FLAG;
511                                 }
512                                 else if (((src & 0x8000L) != 0L)
513                                          && ((dst & 0x8000L) != 0L))
514                                 {
515                                         flags |= C_FLAG;
516                                 }
517                         }
518                         else
519                         {
520                                 if ((res & 0xFFFFL) == 0L)
521                                 {
522                                         flags |= Z_FLAG;
523                                 }
524                                 if (((src & 0x8000L) != 0L)
525                                     && ((dst & 0x8000L) != 0L))
526                                 {
527                                         flags |= V_FLAG;
528                                 }
529                                 if ((dst & 0x8000L) != 0L
530                                     || (src & 0x8000L) != 0L)
531                                 {
532                                         flags |= C_FLAG;
533                                 }
534                         }
535                         break;
536                 case 4:
537                         if ((res & 0x80000000L) != 0L)
538                         {
539                                 flags |= N_FLAG;
540                                 if (((src & 0x80000000L) == 0L)
541                                     && ((dst & 0x80000000L) == 0L))
542                                 {
543                                         flags |= V_FLAG;
544                                 }
545                                 else if (((src & 0x80000000L) != 0L) &&
546                                          ((dst & 0x80000000L) != 0L))
547                                 {
548                                         flags |= C_FLAG;
549                                 }
550                         }
551                         else
552                         {
553                                 if (res == 0L)
554                                         flags |= Z_FLAG;
555                                 if (((src & 0x80000000L) != 0L)
556                                     && ((dst & 0x80000000L) != 0L))
557                                         flags |= V_FLAG;
558                                 if ((dst & 0x80000000L) != 0L
559                                     || (src & 0x80000000L) != 0L)
560                                         flags |= C_FLAG;
561                         }
562                         break;
563                 default:
564                         break;
565         }
566
567         if (env->cc_op == CC_OP_SUB
568             || env->cc_op == CC_OP_CMP) {
569                 flags ^= C_FLAG;
570         }
571         evaluate_flags_writeback(flags);
572 }
573
574 void helper_top_evaluate_flags(void)
575 {
576         switch (env->cc_op)
577         {
578                 case CC_OP_MCP:
579                         helper_evaluate_flags_mcp();
580                         break;
581                 case CC_OP_MULS:
582                         helper_evaluate_flags_muls();
583                         break;
584                 case CC_OP_MULU:
585                         helper_evaluate_flags_mulu();
586                         break;
587                 case CC_OP_MOVE:
588                 case CC_OP_AND:
589                 case CC_OP_OR:
590                 case CC_OP_XOR:
591                 case CC_OP_ASR:
592                 case CC_OP_LSR:
593                 case CC_OP_LSL:
594                         switch (env->cc_size)
595                         {
596                                 case 4:
597                                         helper_evaluate_flags_move_4();
598                                         break;
599                                 case 2:
600                                         helper_evaluate_flags_move_2();
601                                         break;
602                                 default:
603                                         helper_evaluate_flags();
604                                         break;
605                         }
606                         break;
607                 case CC_OP_FLAGS:
608                         /* live.  */
609                         break;
610                 default:
611                 {
612                         switch (env->cc_size)
613                         {
614                                 case 4:
615                                         helper_evaluate_flags_alu_4();
616                                         break;
617                                 default:
618                                         helper_evaluate_flags();
619                                         break;
620                         }
621                 }
622                 break;
623         }
624 }