|
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, write to the Free Software |
|
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
20 */ |
|
21 |
|
22 #include <stdio.h> |
|
23 #include <string.h> |
|
24 |
|
25 #include "config.h" |
|
26 #include "cpu.h" |
|
27 #include "mmu.h" |
|
28 #include "exec-all.h" |
|
29 #include "host-utils.h" |
|
30 |
|
31 #define D(x) |
|
32 |
|
33 #if defined(CONFIG_USER_ONLY) |
|
34 |
|
35 void do_interrupt (CPUState *env) |
|
36 { |
|
37 env->exception_index = -1; |
|
38 env->pregs[PR_ERP] = env->pc; |
|
39 } |
|
40 |
|
41 int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw, |
|
42 int mmu_idx, int is_softmmu) |
|
43 { |
|
44 env->exception_index = 0xaa; |
|
45 env->pregs[PR_EDA] = address; |
|
46 cpu_dump_state(env, stderr, fprintf, 0); |
|
47 return 1; |
|
48 } |
|
49 |
|
50 target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) |
|
51 { |
|
52 return addr; |
|
53 } |
|
54 |
|
55 #else /* !CONFIG_USER_ONLY */ |
|
56 |
|
57 |
|
58 static void cris_shift_ccs(CPUState *env) |
|
59 { |
|
60 uint32_t ccs; |
|
61 /* Apply the ccs shift. */ |
|
62 ccs = env->pregs[PR_CCS]; |
|
63 ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; |
|
64 env->pregs[PR_CCS] = ccs; |
|
65 } |
|
66 |
|
67 int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, |
|
68 int mmu_idx, int is_softmmu) |
|
69 { |
|
70 struct cris_mmu_result_t res; |
|
71 int prot, miss; |
|
72 int r = -1; |
|
73 target_ulong phy; |
|
74 |
|
75 D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw)); |
|
76 address &= TARGET_PAGE_MASK; |
|
77 miss = cris_mmu_translate(&res, env, address, rw, mmu_idx); |
|
78 if (miss) |
|
79 { |
|
80 if (env->exception_index == EXCP_BUSFAULT) |
|
81 cpu_abort(env, |
|
82 "CRIS: Illegal recursive bus fault." |
|
83 "addr=%x rw=%d\n", |
|
84 address, rw); |
|
85 |
|
86 env->exception_index = EXCP_BUSFAULT; |
|
87 env->fault_vector = res.bf_vec; |
|
88 r = 1; |
|
89 } |
|
90 else |
|
91 { |
|
92 /* |
|
93 * Mask off the cache selection bit. The ETRAX busses do not |
|
94 * see the top bit. |
|
95 */ |
|
96 phy = res.phy & ~0x80000000; |
|
97 prot = res.prot; |
|
98 r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu); |
|
99 } |
|
100 if (r > 0) |
|
101 D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x" |
|
102 " phy=%x ismmu=%d vec=%x pc=%x\n", |
|
103 __func__, r, env->interrupt_request, |
|
104 address, res.phy, is_softmmu, res.bf_vec, env->pc)); |
|
105 return r; |
|
106 } |
|
107 |
|
108 void do_interrupt(CPUState *env) |
|
109 { |
|
110 int ex_vec = -1; |
|
111 |
|
112 D(fprintf (logfile, "exception index=%d interrupt_req=%d\n", |
|
113 env->exception_index, |
|
114 env->interrupt_request)); |
|
115 |
|
116 switch (env->exception_index) |
|
117 { |
|
118 case EXCP_BREAK: |
|
119 /* These exceptions are genereated by the core itself. |
|
120 ERP should point to the insn following the brk. */ |
|
121 ex_vec = env->trap_vector; |
|
122 env->pregs[PR_ERP] = env->pc; |
|
123 break; |
|
124 |
|
125 case EXCP_NMI: |
|
126 /* NMI is hardwired to vector zero. */ |
|
127 ex_vec = 0; |
|
128 env->pregs[PR_CCS] &= ~M_FLAG; |
|
129 env->pregs[PR_NRP] = env->pc; |
|
130 break; |
|
131 |
|
132 case EXCP_BUSFAULT: |
|
133 ex_vec = env->fault_vector; |
|
134 env->pregs[PR_ERP] = env->pc; |
|
135 break; |
|
136 |
|
137 default: |
|
138 /* The interrupt controller gives us the vector. */ |
|
139 ex_vec = env->interrupt_vector; |
|
140 /* Normal interrupts are taken between |
|
141 TB's. env->pc is valid here. */ |
|
142 env->pregs[PR_ERP] = env->pc; |
|
143 break; |
|
144 } |
|
145 |
|
146 /* Fill in the IDX field. */ |
|
147 env->pregs[PR_EXS] = (ex_vec & 0xff) << 8; |
|
148 |
|
149 if (env->dslot) { |
|
150 D(fprintf(logfile, "excp isr=%x PC=%x ds=%d SP=%x" |
|
151 " ERP=%x pid=%x ccs=%x cc=%d %x\n", |
|
152 ex_vec, env->pc, env->dslot, |
|
153 env->regs[R_SP], |
|
154 env->pregs[PR_ERP], env->pregs[PR_PID], |
|
155 env->pregs[PR_CCS], |
|
156 env->cc_op, env->cc_mask)); |
|
157 /* We loose the btarget, btaken state here so rexec the |
|
158 branch. */ |
|
159 env->pregs[PR_ERP] -= env->dslot; |
|
160 /* Exception starts with dslot cleared. */ |
|
161 env->dslot = 0; |
|
162 } |
|
163 |
|
164 env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4); |
|
165 |
|
166 if (env->pregs[PR_CCS] & U_FLAG) { |
|
167 /* Swap stack pointers. */ |
|
168 env->pregs[PR_USP] = env->regs[R_SP]; |
|
169 env->regs[R_SP] = env->ksp; |
|
170 } |
|
171 |
|
172 /* Apply the CRIS CCS shift. Clears U if set. */ |
|
173 cris_shift_ccs(env); |
|
174 D(fprintf (logfile, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n", |
|
175 __func__, env->pc, ex_vec, |
|
176 env->pregs[PR_CCS], |
|
177 env->pregs[PR_PID], |
|
178 env->pregs[PR_ERP])); |
|
179 } |
|
180 |
|
181 target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) |
|
182 { |
|
183 uint32_t phy = addr; |
|
184 struct cris_mmu_result_t res; |
|
185 int miss; |
|
186 miss = cris_mmu_translate(&res, env, addr, 0, 0); |
|
187 if (!miss) |
|
188 phy = res.phy; |
|
189 D(fprintf(stderr, "%s %x -> %x\n", __func__, addr, phy)); |
|
190 return phy; |
|
191 } |
|
192 #endif |