Statistics
| Branch: | Revision:

root / target-cris / helper.c @ 43dc2a64

History | View | Annotate | Download (6.4 kB)

1
/*
2
 *  CRIS helper routines.
3
 *
4
 *  Copyright (c) 2007 AXIS Communications AB
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, see <http://www.gnu.org/licenses/>.
19
 */
20

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

    
24
#include "config.h"
25
#include "cpu.h"
26
#include "mmu.h"
27
#include "exec-all.h"
28
#include "host-utils.h"
29

    
30

    
31
//#define CRIS_HELPER_DEBUG
32

    
33

    
34
#ifdef CRIS_HELPER_DEBUG
35
#define D(x) x
36
#define D_LOG(...) qemu_log(__VA__ARGS__)
37
#else
38
#define D(x)
39
#define D_LOG(...) do { } while (0)
40
#endif
41

    
42
#if defined(CONFIG_USER_ONLY)
43

    
44
void do_interrupt (CPUState *env)
45
{
46
        env->exception_index = -1;
47
        env->pregs[PR_ERP] = env->pc;
48
}
49

    
50
int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
51
                             int mmu_idx, int is_softmmu)
52
{
53
        env->exception_index = 0xaa;
54
        env->pregs[PR_EDA] = address;
55
        cpu_dump_state(env, stderr, fprintf, 0);
56
        return 1;
57
}
58

    
59
#else /* !CONFIG_USER_ONLY */
60

    
61

    
62
static void cris_shift_ccs(CPUState *env)
63
{
64
        uint32_t ccs;
65
        /* Apply the ccs shift.  */
66
        ccs = env->pregs[PR_CCS];
67
        ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff;
68
        env->pregs[PR_CCS] = ccs;
69
}
70

    
71
int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
72
                               int mmu_idx, int is_softmmu)
73
{
74
        struct cris_mmu_result res;
75
        int prot, miss;
76
        int r = -1;
77
        target_ulong phy;
78

    
79
        D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw));
80
        miss = cris_mmu_translate(&res, env, address & TARGET_PAGE_MASK,
81
                                  rw, mmu_idx);
82
        if (miss)
83
        {
84
                if (env->exception_index == EXCP_BUSFAULT)
85
                        cpu_abort(env,
86
                                  "CRIS: Illegal recursive bus fault."
87
                                 "addr=%x rw=%d\n",
88
                                 address, rw);
89

    
90
                env->pregs[PR_EDA] = address;
91
                env->exception_index = EXCP_BUSFAULT;
92
                env->fault_vector = res.bf_vec;
93
                r = 1;
94
        }
95
        else
96
        {
97
                /*
98
                 * Mask off the cache selection bit. The ETRAX busses do not
99
                 * see the top bit.
100
                 */
101
                phy = res.phy & ~0x80000000;
102
                prot = res.prot;
103
                tlb_set_page(env, address & TARGET_PAGE_MASK, phy,
104
                             prot | PAGE_EXEC, mmu_idx, TARGET_PAGE_SIZE);
105
                r = 0;
106
        }
107
        if (r > 0)
108
                D_LOG("%s returns %d irqreq=%x addr=%x"
109
                          " phy=%x ismmu=%d vec=%x pc=%x\n", 
110
                          __func__, r, env->interrupt_request, 
111
                          address, res.phy, is_softmmu, res.bf_vec, env->pc);
112
        return r;
113
}
114

    
115
static void do_interruptv10(CPUState *env)
116
{
117
        int ex_vec = -1;
118

    
119
        D_LOG( "exception index=%d interrupt_req=%d\n",
120
                   env->exception_index,
121
                   env->interrupt_request);
122

    
123
        assert(!(env->pregs[PR_CCS] & PFIX_FLAG));
124
        switch (env->exception_index)
125
        {
126
                case EXCP_BREAK:
127
                        /* These exceptions are genereated by the core itself.
128
                           ERP should point to the insn following the brk.  */
129
                        ex_vec = env->trap_vector;
130
                        env->pregs[PR_ERP] = env->pc;
131
                        break;
132

    
133
                case EXCP_NMI:
134
                        /* NMI is hardwired to vector zero.  */
135
                        ex_vec = 0;
136
                        env->pregs[PR_CCS] &= ~M_FLAG;
137
                        env->pregs[PR_NRP] = env->pc;
138
                        break;
139

    
140
                case EXCP_BUSFAULT:
141
                        cpu_abort(env, "Unhandled busfault");
142
                        break;
143

    
144
                default:
145
                        /* The interrupt controller gives us the vector.  */
146
                        ex_vec = env->interrupt_vector;
147
                        /* Normal interrupts are taken between
148
                           TB's.  env->pc is valid here.  */
149
                        env->pregs[PR_ERP] = env->pc;
150
                        break;
151
        }
152

    
153
        if (env->pregs[PR_CCS] & U_FLAG) {
154
                /* Swap stack pointers.  */
155
                env->pregs[PR_USP] = env->regs[R_SP];
156
                env->regs[R_SP] = env->ksp;
157
        }
158

    
159
        /* Now that we are in kernel mode, load the handlers address.  */
160
        env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
161
        env->locked_irq = 1;
162

    
163
        qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", 
164
                      __func__, env->pc, ex_vec, 
165
                      env->pregs[PR_CCS],
166
                      env->pregs[PR_PID], 
167
                      env->pregs[PR_ERP]);
168
}
169

    
170
void do_interrupt(CPUState *env)
171
{
172
        int ex_vec = -1;
173

    
174
        if (env->pregs[PR_VR] < 32)
175
                return do_interruptv10(env);
176

    
177
        D_LOG( "exception index=%d interrupt_req=%d\n",
178
                   env->exception_index,
179
                   env->interrupt_request);
180

    
181
        switch (env->exception_index)
182
        {
183
                case EXCP_BREAK:
184
                        /* These exceptions are genereated by the core itself.
185
                           ERP should point to the insn following the brk.  */
186
                        ex_vec = env->trap_vector;
187
                        env->pregs[PR_ERP] = env->pc;
188
                        break;
189

    
190
                case EXCP_NMI:
191
                        /* NMI is hardwired to vector zero.  */
192
                        ex_vec = 0;
193
                        env->pregs[PR_CCS] &= ~M_FLAG;
194
                        env->pregs[PR_NRP] = env->pc;
195
                        break;
196

    
197
                case EXCP_BUSFAULT:
198
                        ex_vec = env->fault_vector;
199
                        env->pregs[PR_ERP] = env->pc;
200
                        break;
201

    
202
                default:
203
                        /* The interrupt controller gives us the vector.  */
204
                        ex_vec = env->interrupt_vector;
205
                        /* Normal interrupts are taken between
206
                           TB's.  env->pc is valid here.  */
207
                        env->pregs[PR_ERP] = env->pc;
208
                        break;
209
        }
210

    
211
        /* Fill in the IDX field.  */
212
        env->pregs[PR_EXS] = (ex_vec & 0xff) << 8;
213

    
214
        if (env->dslot) {
215
                D_LOG("excp isr=%x PC=%x ds=%d SP=%x"
216
                          " ERP=%x pid=%x ccs=%x cc=%d %x\n",
217
                          ex_vec, env->pc, env->dslot,
218
                          env->regs[R_SP],
219
                          env->pregs[PR_ERP], env->pregs[PR_PID],
220
                          env->pregs[PR_CCS],
221
                          env->cc_op, env->cc_mask);
222
                /* We loose the btarget, btaken state here so rexec the
223
                   branch.  */
224
                env->pregs[PR_ERP] -= env->dslot;
225
                /* Exception starts with dslot cleared.  */
226
                env->dslot = 0;
227
        }
228
        
229
        if (env->pregs[PR_CCS] & U_FLAG) {
230
                /* Swap stack pointers.  */
231
                env->pregs[PR_USP] = env->regs[R_SP];
232
                env->regs[R_SP] = env->ksp;
233
        }
234

    
235
        /* Apply the CRIS CCS shift. Clears U if set.  */
236
        cris_shift_ccs(env);
237

    
238
        /* Now that we are in kernel mode, load the handlers address.  */
239
        env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
240

    
241
        D_LOG("%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
242
                   __func__, env->pc, ex_vec,
243
                   env->pregs[PR_CCS],
244
                   env->pregs[PR_PID], 
245
                   env->pregs[PR_ERP]);
246
}
247

    
248
target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
249
{
250
        uint32_t phy = addr;
251
        struct cris_mmu_result res;
252
        int miss;
253
        miss = cris_mmu_translate(&res, env, addr, 0, 0);
254
        if (!miss)
255
                phy = res.phy;
256
        D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy));
257
        return phy;
258
}
259
#endif