Statistics
| Branch: | Revision:

root / target-cris / op_helper.c @ bf443337

History | View | Annotate | Download (12.1 kB)

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
}