Statistics
| Branch: | Revision:

root / target-cris / op_helper.c @ e2eef170

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 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 (__builtin_expect(ret, 0)) {
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
        cris_mmu_flush_pid(env, pid);
95
#endif
96
}
97

    
98
void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2)
99
{
100
        (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); 
101
}
102

    
103
void helper_dummy(void)
104
{
105

    
106
}
107

    
108
/* Used by the tlb decoder.  */
109
#define EXTRACT_FIELD(src, start, end) \
110
            (((src) >> start) & ((1 << (end - start + 1)) - 1))
111

    
112
void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
113
{
114
        uint32_t srs;
115
        srs = env->pregs[PR_SRS];
116
        srs &= 3;
117
        env->sregs[srs][sreg] = env->regs[reg];
118

    
119
#if !defined(CONFIG_USER_ONLY)
120
        if (srs == 1 || srs == 2) {
121
                if (sreg == 6) {
122
                        /* Writes to tlb-hi write to mm_cause as a side 
123
                           effect.  */
124
                        env->sregs[SFR_RW_MM_TLB_HI] = T0;
125
                        env->sregs[SFR_R_MM_CAUSE] = T0;
126
                }
127
                else if (sreg == 5) {
128
                        uint32_t set;
129
                        uint32_t idx;
130
                        uint32_t lo, hi;
131
                        uint32_t vaddr;
132
                        int tlb_v;
133

    
134
                        idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
135
                        set >>= 4;
136
                        set &= 3;
137

    
138
                        idx &= 15;
139
                        /* We've just made a write to tlb_lo.  */
140
                        lo = env->sregs[SFR_RW_MM_TLB_LO];
141
                        /* Writes are done via r_mm_cause.  */
142
                        hi = env->sregs[SFR_R_MM_CAUSE];
143

    
144
                        vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi,
145
                                              13, 31);
146
                        vaddr <<= TARGET_PAGE_BITS;
147
                        tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo,
148
                                            3, 3);
149
                        env->tlbsets[srs - 1][set][idx].lo = lo;
150
                        env->tlbsets[srs - 1][set][idx].hi = hi;
151

    
152
                        D(fprintf(logfile, 
153
                                  "tlb flush vaddr=%x v=%d pc=%x\n", 
154
                                  vaddr, tlb_v, env->pc));
155
                        tlb_flush_page(env, vaddr);
156
                }
157
        }
158
#endif
159
}
160

    
161
void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg)
162
{
163
        uint32_t srs;
164
        env->pregs[PR_SRS] &= 3;
165
        srs = env->pregs[PR_SRS];
166
        
167
#if !defined(CONFIG_USER_ONLY)
168
        if (srs == 1 || srs == 2)
169
        {
170
                uint32_t set;
171
                uint32_t idx;
172
                uint32_t lo, hi;
173

    
174
                idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
175
                set >>= 4;
176
                set &= 3;
177
                idx &= 15;
178

    
179
                /* Update the mirror regs.  */
180
                hi = env->tlbsets[srs - 1][set][idx].hi;
181
                lo = env->tlbsets[srs - 1][set][idx].lo;
182
                env->sregs[SFR_RW_MM_TLB_HI] = hi;
183
                env->sregs[SFR_RW_MM_TLB_LO] = lo;
184
        }
185
#endif
186
        env->regs[reg] = env->sregs[srs][sreg];
187
        RETURN();
188
}
189

    
190
static void cris_ccs_rshift(CPUState *env)
191
{
192
        uint32_t ccs;
193

    
194
        /* Apply the ccs shift.  */
195
        ccs = env->pregs[PR_CCS];
196
        ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
197
        if (ccs & U_FLAG)
198
        {
199
                /* Enter user mode.  */
200
                env->ksp = env->regs[R_SP];
201
                env->regs[R_SP] = env->pregs[PR_USP];
202
        }
203

    
204
        env->pregs[PR_CCS] = ccs;
205
}
206

    
207
void helper_rfe(void)
208
{
209
        int rflag = env->pregs[PR_CCS] & R_FLAG;
210

    
211
        D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 
212
                 env->pregs[PR_ERP], env->pregs[PR_PID],
213
                 env->pregs[PR_CCS],
214
                 env->btarget));
215

    
216
        cris_ccs_rshift(env);
217

    
218
        /* RFE sets the P_FLAG only if the R_FLAG is not set.  */
219
        if (!rflag)
220
                env->pregs[PR_CCS] |= P_FLAG;
221
}
222

    
223
void helper_store(uint32_t a0)
224
{
225
        if (env->pregs[PR_CCS] & P_FLAG )
226
        {
227
                cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n",
228
                          env->pc, a0);
229
        }
230
}
231

    
232
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
233
                          int is_asi)
234
{
235
        D(printf("%s addr=%x w=%d ex=%d asi=%d\n", 
236
                __func__, addr, is_write, is_exec, is_asi));
237
}
238

    
239
static void evaluate_flags_writeback(uint32_t flags)
240
{
241
        int x;
242

    
243
        /* Extended arithmetics, leave the z flag alone.  */
244
        x = env->cc_x;
245
        if ((x || env->cc_op == CC_OP_ADDC)
246
            && flags & Z_FLAG)
247
                env->cc_mask &= ~Z_FLAG;
248

    
249
        /* all insn clear the x-flag except setf or clrf.  */
250
        env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
251
        flags &= env->cc_mask;
252
        env->pregs[PR_CCS] |= flags;
253
}
254

    
255
void helper_evaluate_flags_muls(void)
256
{
257
        uint32_t src;
258
        uint32_t dst;
259
        uint32_t res;
260
        uint32_t flags = 0;
261
        int64_t tmp;
262
        int32_t mof;
263
        int dneg;
264

    
265
        src = env->cc_src;
266
        dst = env->cc_dest;
267
        res = env->cc_result;
268

    
269
        dneg = ((int32_t)res) < 0;
270

    
271
        mof = env->pregs[PR_MOF];
272
        tmp = mof;
273
        tmp <<= 32;
274
        tmp |= res;
275
        if (tmp == 0)
276
                flags |= Z_FLAG;
277
        else if (tmp < 0)
278
                flags |= N_FLAG;
279
        if ((dneg && mof != -1)
280
            || (!dneg && mof != 0))
281
                flags |= V_FLAG;
282
        evaluate_flags_writeback(flags);
283
}
284

    
285
void  helper_evaluate_flags_mulu(void)
286
{
287
        uint32_t src;
288
        uint32_t dst;
289
        uint32_t res;
290
        uint32_t flags = 0;
291
        uint64_t tmp;
292
        uint32_t mof;
293

    
294
        src = env->cc_src;
295
        dst = env->cc_dest;
296
        res = env->cc_result;
297

    
298
        mof = env->pregs[PR_MOF];
299
        tmp = mof;
300
        tmp <<= 32;
301
        tmp |= res;
302
        if (tmp == 0)
303
                flags |= Z_FLAG;
304
        else if (tmp >> 63)
305
                flags |= N_FLAG;
306
        if (mof)
307
                flags |= V_FLAG;
308

    
309
        evaluate_flags_writeback(flags);
310
}
311

    
312
void  helper_evaluate_flags_mcp(void)
313
{
314
        uint32_t src;
315
        uint32_t dst;
316
        uint32_t res;
317
        uint32_t flags = 0;
318

    
319
        src = env->cc_src;
320
        dst = env->cc_dest;
321
        res = env->cc_result;
322

    
323
        if ((res & 0x80000000L) != 0L)
324
        {
325
                flags |= N_FLAG;
326
                if (((src & 0x80000000L) == 0L)
327
                    && ((dst & 0x80000000L) == 0L))
328
                {
329
                        flags |= V_FLAG;
330
                }
331
                else if (((src & 0x80000000L) != 0L) &&
332
                         ((dst & 0x80000000L) != 0L))
333
                {
334
                        flags |= R_FLAG;
335
                }
336
        }
337
        else
338
        {
339
                if (res == 0L)
340
                        flags |= Z_FLAG;
341
                if (((src & 0x80000000L) != 0L)
342
                    && ((dst & 0x80000000L) != 0L))
343
                        flags |= V_FLAG;
344
                if ((dst & 0x80000000L) != 0L
345
                    || (src & 0x80000000L) != 0L)
346
                        flags |= R_FLAG;
347
        }
348

    
349
        evaluate_flags_writeback(flags);
350
}
351

    
352
void  helper_evaluate_flags_alu_4(void)
353
{
354
        uint32_t src;
355
        uint32_t dst;
356
        uint32_t res;
357
        uint32_t flags = 0;
358

    
359
        src = env->cc_src;
360
        dst = env->cc_dest;
361

    
362
        /* Reconstruct the result.  */
363
        switch (env->cc_op)
364
        {
365
                case CC_OP_SUB:
366
                        res = dst - src;
367
                        break;
368
                case CC_OP_ADD:
369
                        res = dst + src;
370
                        break;
371
                default:
372
                        res = env->cc_result;
373
                        break;
374
        }
375

    
376
        if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
377
                src = ~src;
378

    
379
        if ((res & 0x80000000L) != 0L)
380
        {
381
                flags |= N_FLAG;
382
                if (((src & 0x80000000L) == 0L)
383
                    && ((dst & 0x80000000L) == 0L))
384
                {
385
                        flags |= V_FLAG;
386
                }
387
                else if (((src & 0x80000000L) != 0L) &&
388
                         ((dst & 0x80000000L) != 0L))
389
                {
390
                        flags |= C_FLAG;
391
                }
392
        }
393
        else
394
        {
395
                if (res == 0L)
396
                        flags |= Z_FLAG;
397
                if (((src & 0x80000000L) != 0L)
398
                    && ((dst & 0x80000000L) != 0L))
399
                        flags |= V_FLAG;
400
                if ((dst & 0x80000000L) != 0L
401
                    || (src & 0x80000000L) != 0L)
402
                        flags |= C_FLAG;
403
        }
404

    
405
        if (env->cc_op == CC_OP_SUB
406
            || env->cc_op == CC_OP_CMP) {
407
                flags ^= C_FLAG;
408
        }
409
        evaluate_flags_writeback(flags);
410
}
411

    
412
void  helper_evaluate_flags_move_4 (void)
413
{
414
        uint32_t res;
415
        uint32_t flags = 0;
416

    
417
        res = env->cc_result;
418

    
419
        if ((int32_t)res < 0)
420
                flags |= N_FLAG;
421
        else if (res == 0L)
422
                flags |= Z_FLAG;
423

    
424
        evaluate_flags_writeback(flags);
425
}
426
void  helper_evaluate_flags_move_2 (void)
427
{
428
        uint32_t src;
429
        uint32_t flags = 0;
430
        uint16_t res;
431

    
432
        src = env->cc_src;
433
        res = env->cc_result;
434

    
435
        if ((int16_t)res < 0L)
436
                flags |= N_FLAG;
437
        else if (res == 0)
438
                flags |= Z_FLAG;
439

    
440
        evaluate_flags_writeback(flags);
441
}
442

    
443
/* TODO: This is expensive. We could split things up and only evaluate part of
444
   CCR on a need to know basis. For now, we simply re-evaluate everything.  */
445
void helper_evaluate_flags (void)
446
{
447
        uint32_t src;
448
        uint32_t dst;
449
        uint32_t res;
450
        uint32_t flags = 0;
451

    
452
        src = env->cc_src;
453
        dst = env->cc_dest;
454
        res = env->cc_result;
455

    
456
        if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
457
                src = ~src;
458

    
459
        /* Now, evaluate the flags. This stuff is based on
460
           Per Zander's CRISv10 simulator.  */
461
        switch (env->cc_size)
462
        {
463
                case 1:
464
                        if ((res & 0x80L) != 0L)
465
                        {
466
                                flags |= N_FLAG;
467
                                if (((src & 0x80L) == 0L)
468
                                    && ((dst & 0x80L) == 0L))
469
                                {
470
                                        flags |= V_FLAG;
471
                                }
472
                                else if (((src & 0x80L) != 0L)
473
                                         && ((dst & 0x80L) != 0L))
474
                                {
475
                                        flags |= C_FLAG;
476
                                }
477
                        }
478
                        else
479
                        {
480
                                if ((res & 0xFFL) == 0L)
481
                                {
482
                                        flags |= Z_FLAG;
483
                                }
484
                                if (((src & 0x80L) != 0L)
485
                                    && ((dst & 0x80L) != 0L))
486
                                {
487
                                        flags |= V_FLAG;
488
                                }
489
                                if ((dst & 0x80L) != 0L
490
                                    || (src & 0x80L) != 0L)
491
                                {
492
                                        flags |= C_FLAG;
493
                                }
494
                        }
495
                        break;
496
                case 2:
497
                        if ((res & 0x8000L) != 0L)
498
                        {
499
                                flags |= N_FLAG;
500
                                if (((src & 0x8000L) == 0L)
501
                                    && ((dst & 0x8000L) == 0L))
502
                                {
503
                                        flags |= V_FLAG;
504
                                }
505
                                else if (((src & 0x8000L) != 0L)
506
                                         && ((dst & 0x8000L) != 0L))
507
                                {
508
                                        flags |= C_FLAG;
509
                                }
510
                        }
511
                        else
512
                        {
513
                                if ((res & 0xFFFFL) == 0L)
514
                                {
515
                                        flags |= Z_FLAG;
516
                                }
517
                                if (((src & 0x8000L) != 0L)
518
                                    && ((dst & 0x8000L) != 0L))
519
                                {
520
                                        flags |= V_FLAG;
521
                                }
522
                                if ((dst & 0x8000L) != 0L
523
                                    || (src & 0x8000L) != 0L)
524
                                {
525
                                        flags |= C_FLAG;
526
                                }
527
                        }
528
                        break;
529
                case 4:
530
                        if ((res & 0x80000000L) != 0L)
531
                        {
532
                                flags |= N_FLAG;
533
                                if (((src & 0x80000000L) == 0L)
534
                                    && ((dst & 0x80000000L) == 0L))
535
                                {
536
                                        flags |= V_FLAG;
537
                                }
538
                                else if (((src & 0x80000000L) != 0L) &&
539
                                         ((dst & 0x80000000L) != 0L))
540
                                {
541
                                        flags |= C_FLAG;
542
                                }
543
                        }
544
                        else
545
                        {
546
                                if (res == 0L)
547
                                        flags |= Z_FLAG;
548
                                if (((src & 0x80000000L) != 0L)
549
                                    && ((dst & 0x80000000L) != 0L))
550
                                        flags |= V_FLAG;
551
                                if ((dst & 0x80000000L) != 0L
552
                                    || (src & 0x80000000L) != 0L)
553
                                        flags |= C_FLAG;
554
                        }
555
                        break;
556
                default:
557
                        break;
558
        }
559

    
560
        if (env->cc_op == CC_OP_SUB
561
            || env->cc_op == CC_OP_CMP) {
562
                flags ^= C_FLAG;
563
        }
564
        evaluate_flags_writeback(flags);
565
}
566

    
567
void helper_top_evaluate_flags(void)
568
{
569
        switch (env->cc_op)
570
        {
571
                case CC_OP_MCP:
572
                        helper_evaluate_flags_mcp();
573
                        break;
574
                case CC_OP_MULS:
575
                        helper_evaluate_flags_muls();
576
                        break;
577
                case CC_OP_MULU:
578
                        helper_evaluate_flags_mulu();
579
                        break;
580
                case CC_OP_MOVE:
581
                case CC_OP_AND:
582
                case CC_OP_OR:
583
                case CC_OP_XOR:
584
                case CC_OP_ASR:
585
                case CC_OP_LSR:
586
                case CC_OP_LSL:
587
                        switch (env->cc_size)
588
                        {
589
                                case 4:
590
                                        helper_evaluate_flags_move_4();
591
                                        break;
592
                                case 2:
593
                                        helper_evaluate_flags_move_2();
594
                                        break;
595
                                default:
596
                                        helper_evaluate_flags();
597
                                        break;
598
                        }
599
                        break;
600
                case CC_OP_FLAGS:
601
                        /* live.  */
602
                        break;
603
                default:
604
                {
605
                        switch (env->cc_size)
606
                        {
607
                                case 4:
608
                                        helper_evaluate_flags_alu_4();
609
                                        break;
610
                                default:
611
                                        helper_evaluate_flags();
612
                                        break;
613
                        }
614
                }
615
                break;
616
        }
617
}