Statistics
| Branch: | Revision:

root / target-cris / op_helper.c @ 9b7b85d2

History | View | Annotate | Download (11 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

    
26
#define MMUSUFFIX _mmu
27

    
28
#define SHIFT 0
29
#include "softmmu_template.h"
30

    
31
#define SHIFT 1
32
#include "softmmu_template.h"
33

    
34
#define SHIFT 2
35
#include "softmmu_template.h"
36

    
37
#define SHIFT 3
38
#include "softmmu_template.h"
39

    
40
#define D(x)
41

    
42
/* Try to fill the TLB and return an exception if error. If retaddr is
43
   NULL, it means that the function was called in C code (i.e. not
44
   from generated code or from helper.c) */
45
/* XXX: fix it to restore all registers */
46
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
47
{
48
    TranslationBlock *tb;
49
    CPUState *saved_env;
50
    unsigned long pc;
51
    int ret;
52

    
53
    /* XXX: hack to restore env in all cases, even if not called from
54
       generated code */
55
    saved_env = env;
56
    env = cpu_single_env;
57

    
58
    D(fprintf(logfile, "%s pc=%x tpc=%x ra=%x\n", __func__, 
59
             env->pc, env->debug1, retaddr));
60
    ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
61
    if (__builtin_expect(ret, 0)) {
62
        if (retaddr) {
63
            /* now we have a real cpu fault */
64
            pc = (unsigned long)retaddr;
65
            tb = tb_find_pc(pc);
66
            if (tb) {
67
                /* the PC is inside the translated code. It means that we have
68
                   a virtual CPU fault */
69
                cpu_restore_state(tb, env, pc, NULL);
70
            }
71
        }
72
        cpu_loop_exit();
73
    }
74
    env = saved_env;
75
}
76

    
77
void helper_raise_exception(uint32_t index)
78
{
79
        env->exception_index = index;
80
        cpu_loop_exit();
81
}
82

    
83
void helper_tlb_flush_pid(uint32_t pid)
84
{
85
#if !defined(CONFIG_USER_ONLY)
86
        cris_mmu_flush_pid(env, pid);
87
#endif
88
}
89

    
90
void helper_tlb_flush(void)
91
{
92
        tlb_flush(env, 1);
93
}
94

    
95
void helper_dump(uint32_t a0, uint32_t a1)
96
{
97
        (fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1)); 
98
}
99

    
100
void helper_dummy(void)
101
{
102

    
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] = T0;
122
                        env->sregs[SFR_R_MM_CAUSE] = T0;
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
        D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n", 
207
                 env->pregs[PR_ERP], env->pregs[PR_PID],
208
                 env->pregs[PR_CCS],
209
                 env->btarget));
210

    
211
        cris_ccs_rshift(env);
212

    
213
        /* RFE sets the P_FLAG only if the R_FLAG is not set.  */
214
        if (!(env->pregs[PR_CCS] & R_FLAG))
215
                env->pregs[PR_CCS] |= P_FLAG;
216
}
217

    
218
void helper_store(uint32_t a0)
219
{
220
        if (env->pregs[PR_CCS] & P_FLAG )
221
        {
222
                cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n",
223
                          env->pc, a0);
224
        }
225
}
226

    
227
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
228
                          int is_asi)
229
{
230
        D(printf("%s addr=%x w=%d ex=%d asi=%d\n", 
231
                __func__, addr, is_write, is_exec, is_asi));
232
}
233

    
234
static void evaluate_flags_writeback(uint32_t flags)
235
{
236
        int x;
237

    
238
        /* Extended arithmetics, leave the z flag alone.  */
239
        env->debug3 = env->pregs[PR_CCS];
240

    
241
        if (env->cc_x_live)
242
                x = env->cc_x;
243
        else
244
                x = env->pregs[PR_CCS] & X_FLAG;
245

    
246
        if ((x || env->cc_op == CC_OP_ADDC)
247
            && flags & Z_FLAG)
248
                env->cc_mask &= ~Z_FLAG;
249

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

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

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

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

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

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

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

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

    
310
        evaluate_flags_writeback(flags);
311
}
312

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

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

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

    
350
        evaluate_flags_writeback(flags);
351
}
352

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

    
360
        src = env->cc_src;
361
        dst = env->cc_dest;
362
        res = env->cc_result;
363

    
364
        if ((res & 0x80000000L) != 0L)
365
        {
366
                flags |= N_FLAG;
367
                if (((src & 0x80000000L) == 0L)
368
                    && ((dst & 0x80000000L) == 0L))
369
                {
370
                        flags |= V_FLAG;
371
                }
372
                else if (((src & 0x80000000L) != 0L) &&
373
                         ((dst & 0x80000000L) != 0L))
374
                {
375
                        flags |= C_FLAG;
376
                }
377
        }
378
        else
379
        {
380
                if (res == 0L)
381
                        flags |= Z_FLAG;
382
                if (((src & 0x80000000L) != 0L)
383
                    && ((dst & 0x80000000L) != 0L))
384
                        flags |= V_FLAG;
385
                if ((dst & 0x80000000L) != 0L
386
                    || (src & 0x80000000L) != 0L)
387
                        flags |= C_FLAG;
388
        }
389

    
390
        if (env->cc_op == CC_OP_SUB
391
            || env->cc_op == CC_OP_CMP) {
392
                flags ^= C_FLAG;
393
        }
394
        evaluate_flags_writeback(flags);
395
}
396

    
397
void  helper_evaluate_flags_move_4 (void)
398
{
399
        uint32_t src;
400
        uint32_t res;
401
        uint32_t flags = 0;
402

    
403
        src = env->cc_src;
404
        res = env->cc_result;
405

    
406
        if ((int32_t)res < 0)
407
                flags |= N_FLAG;
408
        else if (res == 0L)
409
                flags |= Z_FLAG;
410

    
411
        evaluate_flags_writeback(flags);
412
}
413
void  helper_evaluate_flags_move_2 (void)
414
{
415
        uint32_t src;
416
        uint32_t flags = 0;
417
        uint16_t res;
418

    
419
        src = env->cc_src;
420
        res = env->cc_result;
421

    
422
        if ((int16_t)res < 0L)
423
                flags |= N_FLAG;
424
        else if (res == 0)
425
                flags |= Z_FLAG;
426

    
427
        evaluate_flags_writeback(flags);
428
}
429

    
430
/* TODO: This is expensive. We could split things up and only evaluate part of
431
   CCR on a need to know basis. For now, we simply re-evaluate everything.  */
432
void helper_evaluate_flags (void)
433
{
434
        uint32_t src;
435
        uint32_t dst;
436
        uint32_t res;
437
        uint32_t flags = 0;
438

    
439
        src = env->cc_src;
440
        dst = env->cc_dest;
441
        res = env->cc_result;
442

    
443

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

    
545
        if (env->cc_op == CC_OP_SUB
546
            || env->cc_op == CC_OP_CMP) {
547
                flags ^= C_FLAG;
548
        }
549
        evaluate_flags_writeback(flags);
550
}