Statistics
| Branch: | Revision:

root / target-cris / op_helper.c @ db8d9902

History | View | Annotate | Download (12.6 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_spc_write(uint32_t new_spc)
101
{
102
#if !defined(CONFIG_USER_ONLY)
103
        tlb_flush_page(env, env->pregs[PR_SPC]);
104
        tlb_flush_page(env, new_spc);
105
#endif
106
}
107

    
108
void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2)
109
{
110
        (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); 
111
}
112

    
113
/* Used by the tlb decoder.  */
114
#define EXTRACT_FIELD(src, start, end) \
115
            (((src) >> start) & ((1 << (end - start + 1)) - 1))
116

    
117
void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
118
{
119
        uint32_t srs;
120
        srs = env->pregs[PR_SRS];
121
        srs &= 3;
122
        env->sregs[srs][sreg] = env->regs[reg];
123

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

    
139
                        idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
140
                        set >>= 4;
141
                        set &= 3;
142

    
143
                        idx &= 15;
144
                        /* We've just made a write to tlb_lo.  */
145
                        lo = env->sregs[SFR_RW_MM_TLB_LO];
146
                        /* Writes are done via r_mm_cause.  */
147
                        hi = env->sregs[SFR_R_MM_CAUSE];
148

    
149
                        vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi,
150
                                              13, 31);
151
                        vaddr <<= TARGET_PAGE_BITS;
152
                        tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo,
153
                                            3, 3);
154
                        env->tlbsets[srs - 1][set][idx].lo = lo;
155
                        env->tlbsets[srs - 1][set][idx].hi = hi;
156

    
157
                        D(fprintf(logfile, 
158
                                  "tlb flush vaddr=%x v=%d pc=%x\n", 
159
                                  vaddr, tlb_v, env->pc));
160
                        tlb_flush_page(env, vaddr);
161
                }
162
        }
163
#endif
164
}
165

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

    
179
                idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
180
                set >>= 4;
181
                set &= 3;
182
                idx &= 15;
183

    
184
                /* Update the mirror regs.  */
185
                hi = env->tlbsets[srs - 1][set][idx].hi;
186
                lo = env->tlbsets[srs - 1][set][idx].lo;
187
                env->sregs[SFR_RW_MM_TLB_HI] = hi;
188
                env->sregs[SFR_RW_MM_TLB_LO] = lo;
189
        }
190
#endif
191
        env->regs[reg] = env->sregs[srs][sreg];
192
}
193

    
194
static void cris_ccs_rshift(CPUState *env)
195
{
196
        uint32_t ccs;
197

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

    
208
        env->pregs[PR_CCS] = ccs;
209
}
210

    
211
void helper_rfe(void)
212
{
213
        int rflag = env->pregs[PR_CCS] & R_FLAG;
214

    
215
        D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 
216
                 env->pregs[PR_ERP], env->pregs[PR_PID],
217
                 env->pregs[PR_CCS],
218
                 env->btarget));
219

    
220
        cris_ccs_rshift(env);
221

    
222
        /* RFE sets the P_FLAG only if the R_FLAG is not set.  */
223
        if (!rflag)
224
                env->pregs[PR_CCS] |= P_FLAG;
225
}
226

    
227
void helper_rfn(void)
228
{
229
        int rflag = env->pregs[PR_CCS] & R_FLAG;
230

    
231
        D(fprintf(logfile, "rfn: erp=%x pid=%x ccs=%x btarget=%x\n", 
232
                 env->pregs[PR_ERP], env->pregs[PR_PID],
233
                 env->pregs[PR_CCS],
234
                 env->btarget));
235

    
236
        cris_ccs_rshift(env);
237

    
238
        /* Set the P_FLAG only if the R_FLAG is not set.  */
239
        if (!rflag)
240
                env->pregs[PR_CCS] |= P_FLAG;
241

    
242
    /* Always set the M flag.  */
243
    env->pregs[PR_CCS] |= M_FLAG;
244
}
245

    
246
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
247
                          int is_asi, int size)
248
{
249
        D(printf("%s addr=%x w=%d ex=%d asi=%d, size=%d\n",
250
                __func__, addr, is_write, is_exec, is_asi, size));
251
}
252

    
253
static void evaluate_flags_writeback(uint32_t flags)
254
{
255
        int x;
256

    
257
        /* Extended arithmetics, leave the z flag alone.  */
258
        x = env->cc_x;
259
        if ((x || env->cc_op == CC_OP_ADDC)
260
            && flags & Z_FLAG)
261
                env->cc_mask &= ~Z_FLAG;
262

    
263
        /* all insn clear the x-flag except setf or clrf.  */
264
        env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
265
        flags &= env->cc_mask;
266
        env->pregs[PR_CCS] |= flags;
267
}
268

    
269
void helper_evaluate_flags_muls(void)
270
{
271
        uint32_t src;
272
        uint32_t dst;
273
        uint32_t res;
274
        uint32_t flags = 0;
275
        int64_t tmp;
276
        int32_t mof;
277
        int dneg;
278

    
279
        src = env->cc_src;
280
        dst = env->cc_dest;
281
        res = env->cc_result;
282

    
283
        dneg = ((int32_t)res) < 0;
284

    
285
        mof = env->pregs[PR_MOF];
286
        tmp = mof;
287
        tmp <<= 32;
288
        tmp |= res;
289
        if (tmp == 0)
290
                flags |= Z_FLAG;
291
        else if (tmp < 0)
292
                flags |= N_FLAG;
293
        if ((dneg && mof != -1)
294
            || (!dneg && mof != 0))
295
                flags |= V_FLAG;
296
        evaluate_flags_writeback(flags);
297
}
298

    
299
void  helper_evaluate_flags_mulu(void)
300
{
301
        uint32_t src;
302
        uint32_t dst;
303
        uint32_t res;
304
        uint32_t flags = 0;
305
        uint64_t tmp;
306
        uint32_t mof;
307

    
308
        src = env->cc_src;
309
        dst = env->cc_dest;
310
        res = env->cc_result;
311

    
312
        mof = env->pregs[PR_MOF];
313
        tmp = mof;
314
        tmp <<= 32;
315
        tmp |= res;
316
        if (tmp == 0)
317
                flags |= Z_FLAG;
318
        else if (tmp >> 63)
319
                flags |= N_FLAG;
320
        if (mof)
321
                flags |= V_FLAG;
322

    
323
        evaluate_flags_writeback(flags);
324
}
325

    
326
void  helper_evaluate_flags_mcp(void)
327
{
328
        uint32_t src;
329
        uint32_t dst;
330
        uint32_t res;
331
        uint32_t flags = 0;
332

    
333
        src = env->cc_src;
334
        dst = env->cc_dest;
335
        res = env->cc_result;
336

    
337
        if ((res & 0x80000000L) != 0L)
338
        {
339
                flags |= N_FLAG;
340
                if (((src & 0x80000000L) == 0L)
341
                    && ((dst & 0x80000000L) == 0L))
342
                {
343
                        flags |= V_FLAG;
344
                }
345
                else if (((src & 0x80000000L) != 0L) &&
346
                         ((dst & 0x80000000L) != 0L))
347
                {
348
                        flags |= R_FLAG;
349
                }
350
        }
351
        else
352
        {
353
                if (res == 0L)
354
                        flags |= Z_FLAG;
355
                if (((src & 0x80000000L) != 0L)
356
                    && ((dst & 0x80000000L) != 0L))
357
                        flags |= V_FLAG;
358
                if ((dst & 0x80000000L) != 0L
359
                    || (src & 0x80000000L) != 0L)
360
                        flags |= R_FLAG;
361
        }
362

    
363
        evaluate_flags_writeback(flags);
364
}
365

    
366
void  helper_evaluate_flags_alu_4(void)
367
{
368
        uint32_t src;
369
        uint32_t dst;
370
        uint32_t res;
371
        uint32_t flags = 0;
372

    
373
        src = env->cc_src;
374
        dst = env->cc_dest;
375

    
376
        /* Reconstruct the result.  */
377
        switch (env->cc_op)
378
        {
379
                case CC_OP_SUB:
380
                        res = dst - src;
381
                        break;
382
                case CC_OP_ADD:
383
                        res = dst + src;
384
                        break;
385
                default:
386
                        res = env->cc_result;
387
                        break;
388
        }
389

    
390
        if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
391
                src = ~src;
392

    
393
        if ((res & 0x80000000L) != 0L)
394
        {
395
                flags |= N_FLAG;
396
                if (((src & 0x80000000L) == 0L)
397
                    && ((dst & 0x80000000L) == 0L))
398
                {
399
                        flags |= V_FLAG;
400
                }
401
                else if (((src & 0x80000000L) != 0L) &&
402
                         ((dst & 0x80000000L) != 0L))
403
                {
404
                        flags |= C_FLAG;
405
                }
406
        }
407
        else
408
        {
409
                if (res == 0L)
410
                        flags |= Z_FLAG;
411
                if (((src & 0x80000000L) != 0L)
412
                    && ((dst & 0x80000000L) != 0L))
413
                        flags |= V_FLAG;
414
                if ((dst & 0x80000000L) != 0L
415
                    || (src & 0x80000000L) != 0L)
416
                        flags |= C_FLAG;
417
        }
418

    
419
        if (env->cc_op == CC_OP_SUB
420
            || env->cc_op == CC_OP_CMP) {
421
                flags ^= C_FLAG;
422
        }
423
        evaluate_flags_writeback(flags);
424
}
425

    
426
void  helper_evaluate_flags_move_4 (void)
427
{
428
        uint32_t res;
429
        uint32_t flags = 0;
430

    
431
        res = env->cc_result;
432

    
433
        if ((int32_t)res < 0)
434
                flags |= N_FLAG;
435
        else if (res == 0L)
436
                flags |= Z_FLAG;
437

    
438
        evaluate_flags_writeback(flags);
439
}
440
void  helper_evaluate_flags_move_2 (void)
441
{
442
        uint32_t src;
443
        uint32_t flags = 0;
444
        uint16_t res;
445

    
446
        src = env->cc_src;
447
        res = env->cc_result;
448

    
449
        if ((int16_t)res < 0L)
450
                flags |= N_FLAG;
451
        else if (res == 0)
452
                flags |= Z_FLAG;
453

    
454
        evaluate_flags_writeback(flags);
455
}
456

    
457
/* TODO: This is expensive. We could split things up and only evaluate part of
458
   CCR on a need to know basis. For now, we simply re-evaluate everything.  */
459
void helper_evaluate_flags (void)
460
{
461
        uint32_t src;
462
        uint32_t dst;
463
        uint32_t res;
464
        uint32_t flags = 0;
465

    
466
        src = env->cc_src;
467
        dst = env->cc_dest;
468
        res = env->cc_result;
469

    
470
        if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP)
471
                src = ~src;
472

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

    
574
        if (env->cc_op == CC_OP_SUB
575
            || env->cc_op == CC_OP_CMP) {
576
                flags ^= C_FLAG;
577
        }
578
        evaluate_flags_writeback(flags);
579
}
580

    
581
void helper_top_evaluate_flags(void)
582
{
583
        switch (env->cc_op)
584
        {
585
                case CC_OP_MCP:
586
                        helper_evaluate_flags_mcp();
587
                        break;
588
                case CC_OP_MULS:
589
                        helper_evaluate_flags_muls();
590
                        break;
591
                case CC_OP_MULU:
592
                        helper_evaluate_flags_mulu();
593
                        break;
594
                case CC_OP_MOVE:
595
                case CC_OP_AND:
596
                case CC_OP_OR:
597
                case CC_OP_XOR:
598
                case CC_OP_ASR:
599
                case CC_OP_LSR:
600
                case CC_OP_LSL:
601
                        switch (env->cc_size)
602
                        {
603
                                case 4:
604
                                        helper_evaluate_flags_move_4();
605
                                        break;
606
                                case 2:
607
                                        helper_evaluate_flags_move_2();
608
                                        break;
609
                                default:
610
                                        helper_evaluate_flags();
611
                                        break;
612
                        }
613
                        break;
614
                case CC_OP_FLAGS:
615
                        /* live.  */
616
                        break;
617
                default:
618
                {
619
                        switch (env->cc_size)
620
                        {
621
                                case 4:
622
                                        helper_evaluate_flags_alu_4();
623
                                        break;
624
                                default:
625
                                        helper_evaluate_flags();
626
                                        break;
627
                        }
628
                }
629
                break;
630
        }
631
}