Statistics
| Branch: | Revision:

root / target-m68k / op_helper.c @ 6f06f178

History | View | Annotate | Download (5.7 kB)

1
/*
2
 *  M68K helper routines
3
 *
4
 *  Copyright (c) 2007 CodeSourcery
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
#include "cpu.h"
20
#include "dyngen-exec.h"
21
#include "helpers.h"
22

    
23
#if defined(CONFIG_USER_ONLY)
24

    
25
void do_interrupt(CPUM68KState *env1)
26
{
27
    env1->exception_index = -1;
28
}
29

    
30
void do_interrupt_m68k_hardirq(CPUM68KState *env1)
31
{
32
}
33

    
34
#else
35

    
36
extern int semihosting_enabled;
37

    
38
#include "softmmu_exec.h"
39

    
40
#define MMUSUFFIX _mmu
41

    
42
#define SHIFT 0
43
#include "softmmu_template.h"
44

    
45
#define SHIFT 1
46
#include "softmmu_template.h"
47

    
48
#define SHIFT 2
49
#include "softmmu_template.h"
50

    
51
#define SHIFT 3
52
#include "softmmu_template.h"
53

    
54
/* Try to fill the TLB and return an exception if error. If retaddr is
55
   NULL, it means that the function was called in C code (i.e. not
56
   from generated code or from helper.c) */
57
/* XXX: fix it to restore all registers */
58
void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int mmu_idx,
59
              void *retaddr)
60
{
61
    TranslationBlock *tb;
62
    CPUM68KState *saved_env;
63
    unsigned long pc;
64
    int ret;
65

    
66
    saved_env = env;
67
    env = env1;
68
    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx);
69
    if (unlikely(ret)) {
70
        if (retaddr) {
71
            /* now we have a real cpu fault */
72
            pc = (unsigned long)retaddr;
73
            tb = tb_find_pc(pc);
74
            if (tb) {
75
                /* the PC is inside the translated code. It means that we have
76
                   a virtual CPU fault */
77
                cpu_restore_state(tb, env, pc);
78
            }
79
        }
80
        cpu_loop_exit(env);
81
    }
82
    env = saved_env;
83
}
84

    
85
static void do_rte(void)
86
{
87
    uint32_t sp;
88
    uint32_t fmt;
89

    
90
    sp = env->aregs[7];
91
    fmt = ldl_kernel(sp);
92
    env->pc = ldl_kernel(sp + 4);
93
    sp |= (fmt >> 28) & 3;
94
    env->sr = fmt & 0xffff;
95
    m68k_switch_sp(env);
96
    env->aregs[7] = sp + 8;
97
}
98

    
99
static void do_interrupt_all(int is_hw)
100
{
101
    uint32_t sp;
102
    uint32_t fmt;
103
    uint32_t retaddr;
104
    uint32_t vector;
105

    
106
    fmt = 0;
107
    retaddr = env->pc;
108

    
109
    if (!is_hw) {
110
        switch (env->exception_index) {
111
        case EXCP_RTE:
112
            /* Return from an exception.  */
113
            do_rte();
114
            return;
115
        case EXCP_HALT_INSN:
116
            if (semihosting_enabled
117
                    && (env->sr & SR_S) != 0
118
                    && (env->pc & 3) == 0
119
                    && lduw_code(env->pc - 4) == 0x4e71
120
                    && ldl_code(env->pc) == 0x4e7bf000) {
121
                env->pc += 4;
122
                do_m68k_semihosting(env, env->dregs[0]);
123
                return;
124
            }
125
            env->halted = 1;
126
            env->exception_index = EXCP_HLT;
127
            cpu_loop_exit(env);
128
            return;
129
        }
130
        if (env->exception_index >= EXCP_TRAP0
131
            && env->exception_index <= EXCP_TRAP15) {
132
            /* Move the PC after the trap instruction.  */
133
            retaddr += 2;
134
        }
135
    }
136

    
137
    vector = env->exception_index << 2;
138

    
139
    sp = env->aregs[7];
140

    
141
    fmt |= 0x40000000;
142
    fmt |= (sp & 3) << 28;
143
    fmt |= vector << 16;
144
    fmt |= env->sr;
145

    
146
    env->sr |= SR_S;
147
    if (is_hw) {
148
        env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
149
        env->sr &= ~SR_M;
150
    }
151
    m68k_switch_sp(env);
152

    
153
    /* ??? This could cause MMU faults.  */
154
    sp &= ~3;
155
    sp -= 4;
156
    stl_kernel(sp, retaddr);
157
    sp -= 4;
158
    stl_kernel(sp, fmt);
159
    env->aregs[7] = sp;
160
    /* Jump to vector.  */
161
    env->pc = ldl_kernel(env->vbr + vector);
162
}
163

    
164
void do_interrupt(CPUM68KState *env1)
165
{
166
    CPUM68KState *saved_env;
167

    
168
    saved_env = env;
169
    env = env1;
170
    do_interrupt_all(0);
171
    env = saved_env;
172
}
173

    
174
void do_interrupt_m68k_hardirq(CPUM68KState *env1)
175
{
176
    CPUM68KState *saved_env;
177

    
178
    saved_env = env;
179
    env = env1;
180
    do_interrupt_all(1);
181
    env = saved_env;
182
}
183
#endif
184

    
185
static void raise_exception(int tt)
186
{
187
    env->exception_index = tt;
188
    cpu_loop_exit(env);
189
}
190

    
191
void HELPER(raise_exception)(uint32_t tt)
192
{
193
    raise_exception(tt);
194
}
195

    
196
void HELPER(divu)(CPUM68KState *env, uint32_t word)
197
{
198
    uint32_t num;
199
    uint32_t den;
200
    uint32_t quot;
201
    uint32_t rem;
202
    uint32_t flags;
203

    
204
    num = env->div1;
205
    den = env->div2;
206
    /* ??? This needs to make sure the throwing location is accurate.  */
207
    if (den == 0)
208
        raise_exception(EXCP_DIV0);
209
    quot = num / den;
210
    rem = num % den;
211
    flags = 0;
212
    /* Avoid using a PARAM1 of zero.  This breaks dyngen because it uses
213
       the address of a symbol, and gcc knows symbols can't have address
214
       zero.  */
215
    if (word && quot > 0xffff)
216
        flags |= CCF_V;
217
    if (quot == 0)
218
        flags |= CCF_Z;
219
    else if ((int32_t)quot < 0)
220
        flags |= CCF_N;
221
    env->div1 = quot;
222
    env->div2 = rem;
223
    env->cc_dest = flags;
224
}
225

    
226
void HELPER(divs)(CPUM68KState *env, uint32_t word)
227
{
228
    int32_t num;
229
    int32_t den;
230
    int32_t quot;
231
    int32_t rem;
232
    int32_t flags;
233

    
234
    num = env->div1;
235
    den = env->div2;
236
    if (den == 0)
237
        raise_exception(EXCP_DIV0);
238
    quot = num / den;
239
    rem = num % den;
240
    flags = 0;
241
    if (word && quot != (int16_t)quot)
242
        flags |= CCF_V;
243
    if (quot == 0)
244
        flags |= CCF_Z;
245
    else if (quot < 0)
246
        flags |= CCF_N;
247
    env->div1 = quot;
248
    env->div2 = rem;
249
    env->cc_dest = flags;
250
}