Statistics
| Branch: | Revision:

root / target-m68k / op_helper.c @ a88790a1

History | View | Annotate | Download (5.4 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 "exec.h"
20
#include "helpers.h"
21

    
22
#if defined(CONFIG_USER_ONLY)
23

    
24
void do_interrupt(int is_hw)
25
{
26
    env->exception_index = -1;
27
}
28

    
29
#else
30

    
31
extern int semihosting_enabled;
32

    
33
#define MMUSUFFIX _mmu
34

    
35
#define SHIFT 0
36
#include "softmmu_template.h"
37

    
38
#define SHIFT 1
39
#include "softmmu_template.h"
40

    
41
#define SHIFT 2
42
#include "softmmu_template.h"
43

    
44
#define SHIFT 3
45
#include "softmmu_template.h"
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
    ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
63
    if (unlikely(ret)) {
64
        if (retaddr) {
65
            /* now we have a real cpu fault */
66
            pc = (unsigned long)retaddr;
67
            tb = tb_find_pc(pc);
68
            if (tb) {
69
                /* the PC is inside the translated code. It means that we have
70
                   a virtual CPU fault */
71
                cpu_restore_state(tb, env, pc, NULL);
72
            }
73
        }
74
        cpu_loop_exit();
75
    }
76
    env = saved_env;
77
}
78

    
79
static void do_rte(void)
80
{
81
    uint32_t sp;
82
    uint32_t fmt;
83

    
84
    sp = env->aregs[7];
85
    fmt = ldl_kernel(sp);
86
    env->pc = ldl_kernel(sp + 4);
87
    sp |= (fmt >> 28) & 3;
88
    env->sr = fmt & 0xffff;
89
    m68k_switch_sp(env);
90
    env->aregs[7] = sp + 8;
91
}
92

    
93
void do_interrupt(int is_hw)
94
{
95
    uint32_t sp;
96
    uint32_t fmt;
97
    uint32_t retaddr;
98
    uint32_t vector;
99

    
100
    fmt = 0;
101
    retaddr = env->pc;
102

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

    
131
    vector = env->exception_index << 2;
132

    
133
    sp = env->aregs[7];
134

    
135
    fmt |= 0x40000000;
136
    fmt |= (sp & 3) << 28;
137
    fmt |= vector << 16;
138
    fmt |= env->sr;
139

    
140
    env->sr |= SR_S;
141
    if (is_hw) {
142
        env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
143
        env->sr &= ~SR_M;
144
    }
145
    m68k_switch_sp(env);
146

    
147
    /* ??? This could cause MMU faults.  */
148
    sp &= ~3;
149
    sp -= 4;
150
    stl_kernel(sp, retaddr);
151
    sp -= 4;
152
    stl_kernel(sp, fmt);
153
    env->aregs[7] = sp;
154
    /* Jump to vector.  */
155
    env->pc = ldl_kernel(env->vbr + vector);
156
}
157

    
158
#endif
159

    
160
static void raise_exception(int tt)
161
{
162
    env->exception_index = tt;
163
    cpu_loop_exit();
164
}
165

    
166
void HELPER(raise_exception)(uint32_t tt)
167
{
168
    raise_exception(tt);
169
}
170

    
171
void HELPER(divu)(CPUState *env, uint32_t word)
172
{
173
    uint32_t num;
174
    uint32_t den;
175
    uint32_t quot;
176
    uint32_t rem;
177
    uint32_t flags;
178

    
179
    num = env->div1;
180
    den = env->div2;
181
    /* ??? This needs to make sure the throwing location is accurate.  */
182
    if (den == 0)
183
        raise_exception(EXCP_DIV0);
184
    quot = num / den;
185
    rem = num % den;
186
    flags = 0;
187
    /* Avoid using a PARAM1 of zero.  This breaks dyngen because it uses
188
       the address of a symbol, and gcc knows symbols can't have address
189
       zero.  */
190
    if (word && quot > 0xffff)
191
        flags |= CCF_V;
192
    if (quot == 0)
193
        flags |= CCF_Z;
194
    else if ((int32_t)quot < 0)
195
        flags |= CCF_N;
196
    env->div1 = quot;
197
    env->div2 = rem;
198
    env->cc_dest = flags;
199
}
200

    
201
void HELPER(divs)(CPUState *env, uint32_t word)
202
{
203
    int32_t num;
204
    int32_t den;
205
    int32_t quot;
206
    int32_t rem;
207
    int32_t flags;
208

    
209
    num = env->div1;
210
    den = env->div2;
211
    if (den == 0)
212
        raise_exception(EXCP_DIV0);
213
    quot = num / den;
214
    rem = num % den;
215
    flags = 0;
216
    if (word && quot != (int16_t)quot)
217
        flags |= CCF_V;
218
    if (quot == 0)
219
        flags |= CCF_Z;
220
    else if (quot < 0)
221
        flags |= CCF_N;
222
    env->div1 = quot;
223
    env->div2 = rem;
224
    env->cc_dest = flags;
225
}