Statistics
| Branch: | Revision:

root / target-cris / op_helper.c @ 28de16da

History | View | Annotate | Download (12.4 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 (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)
241
{
242
        D(printf("%s addr=%x w=%d ex=%d asi=%d\n", 
243
                __func__, addr, is_write, is_exec, is_asi));
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
}