Statistics
| Branch: | Revision:

root / target-microblaze / helper.c @ 76cad711

History | View | Annotate | Download (9.5 kB)

1
/*
2
 *  MicroBlaze helper routines.
3
 *
4
 *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>
5
 *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
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, see <http://www.gnu.org/licenses/>.
19
 */
20

    
21
#include "cpu.h"
22
#include "host-utils.h"
23

    
24
#define D(x)
25
#define DMMU(x)
26

    
27
#if defined(CONFIG_USER_ONLY)
28

    
29
void do_interrupt (CPUMBState *env)
30
{
31
    env->exception_index = -1;
32
    env->res_addr = RES_ADDR_NONE;
33
    env->regs[14] = env->sregs[SR_PC];
34
}
35

    
36
int cpu_mb_handle_mmu_fault(CPUMBState * env, target_ulong address, int rw,
37
                            int mmu_idx)
38
{
39
    env->exception_index = 0xaa;
40
    cpu_dump_state(env, stderr, fprintf, 0);
41
    return 1;
42
}
43

    
44
#else /* !CONFIG_USER_ONLY */
45

    
46
int cpu_mb_handle_mmu_fault (CPUMBState *env, target_ulong address, int rw,
47
                             int mmu_idx)
48
{
49
    unsigned int hit;
50
    unsigned int mmu_available;
51
    int r = 1;
52
    int prot;
53

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

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

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

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

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

    
95
            if (env->exception_index == EXCP_MMU) {
96
                cpu_abort(env, "recursive faults\n");
97
            }
98

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

    
112
void do_interrupt(CPUMBState *env)
113
{
114
    uint32_t t;
115

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

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

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

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

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

    
153
        case EXCP_MMU:
154
            env->regs[17] = env->sregs[SR_PC];
155

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

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

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

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

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

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

    
200
#if 0
201
#include "disas/disas.h"
202

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

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

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

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

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

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

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

    
261
hwaddr cpu_get_phys_page_debug(CPUMBState * env, target_ulong addr)
262
{
263
    target_ulong vaddr, paddr = 0;
264
    struct microblaze_mmu_lookup lu;
265
    unsigned int hit;
266

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

    
277
    return paddr;
278
}
279
#endif