Statistics
| Branch: | Revision:

root / target-microblaze / helper.c @ 39bffca2

History | View | Annotate | Download (9.4 kB)

1
/*
2
 *  MicroBlaze helper routines.
3
 *
4
 *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>
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

    
20
#include <stdio.h>
21
#include <string.h>
22
#include <assert.h>
23

    
24
#include "config.h"
25
#include "cpu.h"
26
#include "host-utils.h"
27

    
28
#define D(x)
29
#define DMMU(x)
30

    
31
#if defined(CONFIG_USER_ONLY)
32

    
33
void do_interrupt (CPUState *env)
34
{
35
    env->exception_index = -1;
36
    env->regs[14] = env->sregs[SR_PC];
37
}
38

    
39
int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
40
                            int mmu_idx)
41
{
42
    env->exception_index = 0xaa;
43
    cpu_dump_state(env, stderr, fprintf, 0);
44
    return 1;
45
}
46

    
47
#else /* !CONFIG_USER_ONLY */
48

    
49
int cpu_mb_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
50
                             int mmu_idx)
51
{
52
    unsigned int hit;
53
    unsigned int mmu_available;
54
    int r = 1;
55
    int prot;
56

    
57
    mmu_available = 0;
58
    if (env->pvr.regs[0] & PVR0_USE_MMU) {
59
        mmu_available = 1;
60
        if ((env->pvr.regs[0] & PVR0_PVR_FULL_MASK)
61
            && (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) {
62
            mmu_available = 0;
63
        }
64
    }
65

    
66
    /* Translate if the MMU is available and enabled.  */
67
    if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) {
68
        target_ulong vaddr, paddr;
69
        struct microblaze_mmu_lookup lu;
70

    
71
        hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx);
72
        if (hit) {
73
            vaddr = address & TARGET_PAGE_MASK;
74
            paddr = lu.paddr + vaddr - lu.vaddr;
75

    
76
            DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n",
77
                     mmu_idx, vaddr, paddr, lu.prot));
78
            tlb_set_page(env, vaddr, paddr, lu.prot, mmu_idx, TARGET_PAGE_SIZE);
79
            r = 0;
80
        } else {
81
            env->sregs[SR_EAR] = address;
82
            DMMU(qemu_log("mmu=%d miss v=%x\n", mmu_idx, address));
83

    
84
            switch (lu.err) {
85
                case ERR_PROT:
86
                    env->sregs[SR_ESR] = rw == 2 ? 17 : 16;
87
                    env->sregs[SR_ESR] |= (rw == 1) << 10;
88
                    break;
89
                case ERR_MISS:
90
                    env->sregs[SR_ESR] = rw == 2 ? 19 : 18;
91
                    env->sregs[SR_ESR] |= (rw == 1) << 10;
92
                    break;
93
                default:
94
                    abort();
95
                    break;
96
            }
97

    
98
            if (env->exception_index == EXCP_MMU) {
99
                cpu_abort(env, "recursive faults\n");
100
            }
101

    
102
            /* TLB miss.  */
103
            env->exception_index = EXCP_MMU;
104
        }
105
    } else {
106
        /* MMU disabled or not available.  */
107
        address &= TARGET_PAGE_MASK;
108
        prot = PAGE_BITS;
109
        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
110
        r = 0;
111
    }
112
    return r;
113
}
114

    
115
void do_interrupt(CPUState *env)
116
{
117
    uint32_t t;
118

    
119
    /* IMM flag cannot propagate across a branch and into the dslot.  */
120
    assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG)));
121
    assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG)));
122
/*    assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions.  */
123
    switch (env->exception_index) {
124
        case EXCP_HW_EXCP:
125
            if (!(env->pvr.regs[0] & PVR0_USE_EXC_MASK)) {
126
                qemu_log("Exception raised on system without exceptions!\n");
127
                return;
128
            }
129

    
130
            env->regs[17] = env->sregs[SR_PC] + 4;
131
            env->sregs[SR_ESR] &= ~(1 << 12);
132

    
133
            /* Exception breaks branch + dslot sequence?  */
134
            if (env->iflags & D_FLAG) {
135
                env->sregs[SR_ESR] |= 1 << 12 ;
136
                env->sregs[SR_BTR] = env->btarget;
137
            }
138

    
139
            /* Disable the MMU.  */
140
            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
141
            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
142
            env->sregs[SR_MSR] |= t;
143
            /* Exception in progress.  */
144
            env->sregs[SR_MSR] |= MSR_EIP;
145

    
146
            qemu_log_mask(CPU_LOG_INT,
147
                          "hw exception at pc=%x ear=%x esr=%x iflags=%x\n",
148
                          env->sregs[SR_PC], env->sregs[SR_EAR],
149
                          env->sregs[SR_ESR], env->iflags);
150
            log_cpu_state_mask(CPU_LOG_INT, env, 0);
151
            env->iflags &= ~(IMM_FLAG | D_FLAG);
152
            env->sregs[SR_PC] = 0x20;
153
            break;
154

    
155
        case EXCP_MMU:
156
            env->regs[17] = env->sregs[SR_PC];
157

    
158
            env->sregs[SR_ESR] &= ~(1 << 12);
159
            /* Exception breaks branch + dslot sequence?  */
160
            if (env->iflags & D_FLAG) {
161
                D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm));
162
                env->sregs[SR_ESR] |= 1 << 12 ;
163
                env->sregs[SR_BTR] = env->btarget;
164

    
165
                /* Reexecute the branch.  */
166
                env->regs[17] -= 4;
167
                /* was the branch immprefixed?.  */
168
                if (env->bimm) {
169
                    qemu_log_mask(CPU_LOG_INT,
170
                                  "bimm exception at pc=%x iflags=%x\n",
171
                                  env->sregs[SR_PC], env->iflags);
172
                    env->regs[17] -= 4;
173
                    log_cpu_state_mask(CPU_LOG_INT, env, 0);
174
                }
175
            } else if (env->iflags & IMM_FLAG) {
176
                D(qemu_log("IMM_FLAG set at exception\n"));
177
                env->regs[17] -= 4;
178
            }
179

    
180
            /* Disable the MMU.  */
181
            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
182
            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
183
            env->sregs[SR_MSR] |= t;
184
            /* Exception in progress.  */
185
            env->sregs[SR_MSR] |= MSR_EIP;
186

    
187
            qemu_log_mask(CPU_LOG_INT,
188
                          "exception at pc=%x ear=%x iflags=%x\n",
189
                          env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags);
190
            log_cpu_state_mask(CPU_LOG_INT, env, 0);
191
            env->iflags &= ~(IMM_FLAG | D_FLAG);
192
            env->sregs[SR_PC] = 0x20;
193
            break;
194

    
195
        case EXCP_IRQ:
196
            assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)));
197
            assert(env->sregs[SR_MSR] & MSR_IE);
198
            assert(!(env->iflags & D_FLAG));
199

    
200
            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
201

    
202
#if 0
203
#include "disas.h"
204

205
/* Useful instrumentation when debugging interrupt issues in either
206
   the models or in sw.  */
207
            {
208
                const char *sym;
209

210
                sym = lookup_symbol(env->sregs[SR_PC]);
211
                if (sym
212
                    && (!strcmp("netif_rx", sym)
213
                        || !strcmp("process_backlog", sym))) {
214

215
                    qemu_log(
216
                         "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n",
217
                         env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags,
218
                         sym);
219

220
                    log_cpu_state(env, 0);
221
                }
222
            }
223
#endif
224
            qemu_log_mask(CPU_LOG_INT,
225
                         "interrupt at pc=%x msr=%x %x iflags=%x\n",
226
                         env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
227

    
228
            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \
229
                                    | MSR_UM | MSR_IE);
230
            env->sregs[SR_MSR] |= t;
231

    
232
            env->regs[14] = env->sregs[SR_PC];
233
            env->sregs[SR_PC] = 0x10;
234
            //log_cpu_state_mask(CPU_LOG_INT, env, 0);
235
            break;
236

    
237
        case EXCP_BREAK:
238
        case EXCP_HW_BREAK:
239
            assert(!(env->iflags & IMM_FLAG));
240
            assert(!(env->iflags & D_FLAG));
241
            t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1;
242
            qemu_log_mask(CPU_LOG_INT,
243
                        "break at pc=%x msr=%x %x iflags=%x\n",
244
                        env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags);
245
            log_cpu_state_mask(CPU_LOG_INT, env, 0);
246
            env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM);
247
            env->sregs[SR_MSR] |= t;
248
            env->sregs[SR_MSR] |= MSR_BIP;
249
            if (env->exception_index == EXCP_HW_BREAK) {
250
                env->regs[16] = env->sregs[SR_PC];
251
                env->sregs[SR_MSR] |= MSR_BIP;
252
                env->sregs[SR_PC] = 0x18;
253
            } else
254
                env->sregs[SR_PC] = env->btarget;
255
            break;
256
        default:
257
            cpu_abort(env, "unhandled exception type=%d\n",
258
                      env->exception_index);
259
            break;
260
    }
261
}
262

    
263
target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
264
{
265
    target_ulong vaddr, paddr = 0;
266
    struct microblaze_mmu_lookup lu;
267
    unsigned int hit;
268

    
269
    if (env->sregs[SR_MSR] & MSR_VM) {
270
        hit = mmu_translate(&env->mmu, &lu, addr, 0, 0);
271
        if (hit) {
272
            vaddr = addr & TARGET_PAGE_MASK;
273
            paddr = lu.paddr + vaddr - lu.vaddr;
274
        } else
275
            paddr = 0; /* ???.  */
276
    } else
277
        paddr = addr & TARGET_PAGE_MASK;
278

    
279
    return paddr;
280
}
281
#endif