Statistics
| Branch: | Revision:

root / target-cris / op_helper.c @ 8c99506c

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

    
26
#define MMUSUFFIX _mmu
27
#ifdef __s390__
28
# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
29
#else
30
# define GETPC() (__builtin_return_address(0))
31
#endif
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
#define D(x)
46

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

    
58
    /* XXX: hack to restore env in all cases, even if not called from
59
       generated code */
60
    saved_env = env;
61
    env = cpu_single_env;
62

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

    
82
void helper_raise_exception(uint32_t index)
83
{
84
        env->exception_index = index;
85
        cpu_loop_exit();
86
}
87

    
88
void helper_tlb_flush_pid(uint32_t pid)
89
{
90
#if !defined(CONFIG_USER_ONLY)
91
        cris_mmu_flush_pid(env, pid);
92
#endif
93
}
94

    
95
void helper_tlb_flush(void)
96
{
97
        tlb_flush(env, 1);
98
}
99

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

    
105
void helper_dummy(void)
106
{
107

    
108
}
109

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

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

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

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

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

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

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

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

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

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

    
192
static void cris_ccs_rshift(CPUState *env)
193
{
194
        uint32_t ccs;
195

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

    
206
        env->pregs[PR_CCS] = ccs;
207
}
208

    
209
void helper_rfe(void)
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 (!(env->pregs[PR_CCS] & R_FLAG))
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
        env->debug3 = env->pregs[PR_CCS];
245

    
246
        if (env->cc_x_live)
247
                x = env->cc_x;
248
        else
249
                x = env->pregs[PR_CCS] & X_FLAG;
250

    
251
        if ((x || env->cc_op == CC_OP_ADDC)
252
            && flags & Z_FLAG)
253
                env->cc_mask &= ~Z_FLAG;
254

    
255
        /* all insn clear the x-flag except setf or clrf.  */
256
        env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG);
257
        flags &= env->cc_mask;
258
        env->pregs[PR_CCS] |= flags;
259
}
260

    
261
void helper_evaluate_flags_muls(void)
262
{
263
        uint32_t src;
264
        uint32_t dst;
265
        uint32_t res;
266
        uint32_t flags = 0;
267
        int64_t tmp;
268
        int32_t mof;
269
        int dneg;
270

    
271
        src = env->cc_src;
272
        dst = env->cc_dest;
273
        res = env->cc_result;
274

    
275
        dneg = ((int32_t)res) < 0;
276

    
277
        mof = env->pregs[PR_MOF];
278
        tmp = mof;
279
        tmp <<= 32;
280
        tmp |= res;
281
        if (tmp == 0)
282
                flags |= Z_FLAG;
283
        else if (tmp < 0)
284
                flags |= N_FLAG;
285
        if ((dneg && mof != -1)
286
            || (!dneg && mof != 0))
287
                flags |= V_FLAG;
288
        evaluate_flags_writeback(flags);
289
}
290

    
291
void  helper_evaluate_flags_mulu(void)
292
{
293
        uint32_t src;
294
        uint32_t dst;
295
        uint32_t res;
296
        uint32_t flags = 0;
297
        uint64_t tmp;
298
        uint32_t mof;
299

    
300
        src = env->cc_src;
301
        dst = env->cc_dest;
302
        res = env->cc_result;
303

    
304
        mof = env->pregs[PR_MOF];
305
        tmp = mof;
306
        tmp <<= 32;
307
        tmp |= res;
308
        if (tmp == 0)
309
                flags |= Z_FLAG;
310
        else if (tmp >> 63)
311
                flags |= N_FLAG;
312
        if (mof)
313
                flags |= V_FLAG;
314

    
315
        evaluate_flags_writeback(flags);
316
}
317

    
318
void  helper_evaluate_flags_mcp(void)
319
{
320
        uint32_t src;
321
        uint32_t dst;
322
        uint32_t res;
323
        uint32_t flags = 0;
324

    
325
        src = env->cc_src;
326
        dst = env->cc_dest;
327
        res = env->cc_result;
328

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

    
355
        evaluate_flags_writeback(flags);
356
}
357

    
358
void  helper_evaluate_flags_alu_4(void)
359
{
360
        uint32_t src;
361
        uint32_t dst;
362
        uint32_t res;
363
        uint32_t flags = 0;
364

    
365
        src = env->cc_src;
366
        dst = env->cc_dest;
367
        res = env->cc_result;
368

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

    
395
        if (env->cc_op == CC_OP_SUB
396
            || env->cc_op == CC_OP_CMP) {
397
                flags ^= C_FLAG;
398
        }
399
        evaluate_flags_writeback(flags);
400
}
401

    
402
void  helper_evaluate_flags_move_4 (void)
403
{
404
        uint32_t src;
405
        uint32_t res;
406
        uint32_t flags = 0;
407

    
408
        src = env->cc_src;
409
        res = env->cc_result;
410

    
411
        if ((int32_t)res < 0)
412
                flags |= N_FLAG;
413
        else if (res == 0L)
414
                flags |= Z_FLAG;
415

    
416
        evaluate_flags_writeback(flags);
417
}
418
void  helper_evaluate_flags_move_2 (void)
419
{
420
        uint32_t src;
421
        uint32_t flags = 0;
422
        uint16_t res;
423

    
424
        src = env->cc_src;
425
        res = env->cc_result;
426

    
427
        if ((int16_t)res < 0L)
428
                flags |= N_FLAG;
429
        else if (res == 0)
430
                flags |= Z_FLAG;
431

    
432
        evaluate_flags_writeback(flags);
433
}
434

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

    
444
        src = env->cc_src;
445
        dst = env->cc_dest;
446
        res = env->cc_result;
447

    
448

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

    
550
        if (env->cc_op == CC_OP_SUB
551
            || env->cc_op == CC_OP_CMP) {
552
                flags ^= C_FLAG;
553
        }
554
        evaluate_flags_writeback(flags);
555
}