1 | /* |
2 | * OpenRISC system instructions helper routines |
3 | * |
4 | * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com> |
5 | * Zhizhou Zhang <etouzh@gmail.com> |
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.1 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 "qemu/osdep.h" |
22 | #include "cpu.h" |
23 | #include "exec/exec-all.h" |
24 | #include "exec/helper-proto.h" |
25 | #include "exception.h" |
26 | #include "sysemu/sysemu.h" |
27 | #ifndef CONFIG_USER_ONLY |
28 | #include "hw/boards.h" |
29 | #endif |
30 | |
31 | #define TO_SPR(group, number) (((group) << 11) + (number)) |
32 | |
33 | void HELPER(mtspr)(CPUOpenRISCState *env, target_ulong spr, target_ulong rb) |
34 | { |
35 | #ifndef CONFIG_USER_ONLY |
36 | OpenRISCCPU *cpu = env_archcpu(env); |
37 | CPUState *cs = env_cpu(env); |
38 | target_ulong mr; |
39 | int idx; |
40 | #endif |
41 | |
42 | switch (spr) { |
43 | #ifndef CONFIG_USER_ONLY |
44 | case TO_SPR(0, 11): /* EVBAR */ |
45 | env->evbar = rb; |
46 | break; |
47 | |
48 | case TO_SPR(0, 16): /* NPC */ |
49 | cpu_restore_state(cs, GETPC(), true); |
50 | /* ??? Mirror or1ksim in not trashing delayed branch state |
51 | when "jumping" to the current instruction. */ |
52 | if (env->pc != rb) { |
53 | env->pc = rb; |
54 | env->dflag = 0; |
55 | cpu_loop_exit(cs); |
56 | } |
57 | break; |
58 | |
59 | case TO_SPR(0, 17): /* SR */ |
60 | cpu_set_sr(env, rb); |
61 | break; |
62 | |
63 | case TO_SPR(0, 32): /* EPCR */ |
64 | env->epcr = rb; |
65 | break; |
66 | |
67 | case TO_SPR(0, 48): /* EEAR */ |
68 | env->eear = rb; |
69 | break; |
70 | |
71 | case TO_SPR(0, 64): /* ESR */ |
72 | env->esr = rb; |
73 | break; |
74 | |
75 | case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */ |
76 | idx = (spr - 1024); |
77 | env->shadow_gpr[idx / 32][idx % 32] = rb; |
78 | break; |
79 | |
80 | case TO_SPR(1, 512) ... TO_SPR(1, 512 + TLB_SIZE - 1): /* DTLBW0MR 0-127 */ |
81 | idx = spr - TO_SPR(1, 512); |
82 | mr = env->tlb.dtlb[idx].mr; |
83 | if (mr & 1) { |
84 | tlb_flush_page(cs, mr & TARGET_PAGE_MASK); |
85 | } |
86 | if (rb & 1) { |
87 | tlb_flush_page(cs, rb & TARGET_PAGE_MASK); |
88 | } |
89 | env->tlb.dtlb[idx].mr = rb; |
90 | break; |
91 | case TO_SPR(1, 640) ... TO_SPR(1, 640 + TLB_SIZE - 1): /* DTLBW0TR 0-127 */ |
92 | idx = spr - TO_SPR(1, 640); |
93 | env->tlb.dtlb[idx].tr = rb; |
94 | break; |
95 | case TO_SPR(1, 768) ... TO_SPR(1, 895): /* DTLBW1MR 0-127 */ |
96 | case TO_SPR(1, 896) ... TO_SPR(1, 1023): /* DTLBW1TR 0-127 */ |
97 | case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */ |
98 | case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */ |
99 | case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */ |
100 | case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */ |
101 | break; |
102 | |
103 | case TO_SPR(2, 512) ... TO_SPR(2, 512 + TLB_SIZE - 1): /* ITLBW0MR 0-127 */ |
104 | idx = spr - TO_SPR(2, 512); |
105 | mr = env->tlb.itlb[idx].mr; |
106 | if (mr & 1) { |
107 | tlb_flush_page(cs, mr & TARGET_PAGE_MASK); |
108 | } |
109 | if (rb & 1) { |
110 | tlb_flush_page(cs, rb & TARGET_PAGE_MASK); |
111 | } |
112 | env->tlb.itlb[idx].mr = rb; |
113 | break; |
114 | case TO_SPR(2, 640) ... TO_SPR(2, 640 + TLB_SIZE - 1): /* ITLBW0TR 0-127 */ |
115 | idx = spr - TO_SPR(2, 640); |
116 | env->tlb.itlb[idx].tr = rb; |
117 | break; |
118 | case TO_SPR(2, 768) ... TO_SPR(2, 895): /* ITLBW1MR 0-127 */ |
119 | case TO_SPR(2, 896) ... TO_SPR(2, 1023): /* ITLBW1TR 0-127 */ |
120 | case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */ |
121 | case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */ |
122 | case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */ |
123 | case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */ |
124 | break; |
125 | |
126 | case TO_SPR(5, 1): /* MACLO */ |
127 | env->mac = deposit64(env->mac, 0, 32, rb); |
128 | break; |
129 | case TO_SPR(5, 2): /* MACHI */ |
130 | env->mac = deposit64(env->mac, 32, 32, rb); |
131 | break; |
132 | case TO_SPR(8, 0): /* PMR */ |
133 | env->pmr = rb; |
134 | if (env->pmr & PMR_DME || env->pmr & PMR_SME) { |
135 | cpu_restore_state(cs, GETPC(), true); |
136 | env->pc += 4; |
137 | cs->halted = 1; |
138 | raise_exception(cpu, EXCP_HALTED); |
139 | } |
140 | break; |
141 | case TO_SPR(9, 0): /* PICMR */ |
142 | env->picmr = rb; |
143 | break; |
144 | case TO_SPR(9, 2): /* PICSR */ |
145 | env->picsr &= ~rb; |
146 | break; |
147 | case TO_SPR(10, 0): /* TTMR */ |
148 | { |
149 | if ((env->ttmr & TTMR_M) ^ (rb & TTMR_M)) { |
150 | switch (rb & TTMR_M) { |
151 | case TIMER_NONE: |
152 | cpu_openrisc_count_stop(cpu); |
153 | break; |
154 | case TIMER_INTR: |
155 | case TIMER_SHOT: |
156 | case TIMER_CONT: |
157 | cpu_openrisc_count_start(cpu); |
158 | break; |
159 | default: |
160 | break; |
161 | } |
162 | } |
163 | |
164 | int ip = env->ttmr & TTMR_IP; |
165 | |
166 | if (rb & TTMR_IP) { /* Keep IP bit. */ |
167 | env->ttmr = (rb & ~TTMR_IP) | ip; |
168 | } else { /* Clear IP bit. */ |
169 | env->ttmr = rb & ~TTMR_IP; |
170 | cs->interrupt_request &= ~CPU_INTERRUPT_TIMER; |
171 | } |
172 | |
173 | cpu_openrisc_timer_update(cpu); |
174 | } |
175 | break; |
176 | |
177 | case TO_SPR(10, 1): /* TTCR */ |
178 | cpu_openrisc_count_set(cpu, rb); |
179 | if (env->ttmr & TIMER_NONE) { |
180 | return; |
181 | } |
182 | cpu_openrisc_timer_update(cpu); |
183 | break; |
184 | #endif |
185 | |
186 | case TO_SPR(0, 20): /* FPCSR */ |
187 | cpu_set_fpcsr(env, rb); |
188 | break; |
189 | } |
190 | } |
191 | |
192 | target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, |
193 | target_ulong spr) |
194 | { |
195 | #ifndef CONFIG_USER_ONLY |
196 | MachineState *ms = MACHINE(qdev_get_machine()); |
197 | OpenRISCCPU *cpu = env_archcpu(env); |
198 | CPUState *cs = env_cpu(env); |
199 | int idx; |
200 | #endif |
201 | |
202 | switch (spr) { |
203 | #ifndef CONFIG_USER_ONLY |
204 | case TO_SPR(0, 0): /* VR */ |
205 | return env->vr; |
206 | |
207 | case TO_SPR(0, 1): /* UPR */ |
208 | return env->upr; |
209 | |
210 | case TO_SPR(0, 2): /* CPUCFGR */ |
211 | return env->cpucfgr; |
212 | |
213 | case TO_SPR(0, 3): /* DMMUCFGR */ |
214 | return env->dmmucfgr; |
215 | |
216 | case TO_SPR(0, 4): /* IMMUCFGR */ |
217 | return env->immucfgr; |
218 | |
219 | case TO_SPR(0, 9): /* VR2 */ |
220 | return env->vr2; |
221 | |
222 | case TO_SPR(0, 10): /* AVR */ |
223 | return env->avr; |
224 | |
225 | case TO_SPR(0, 11): /* EVBAR */ |
226 | return env->evbar; |
227 | |
228 | case TO_SPR(0, 16): /* NPC (equals PC) */ |
229 | cpu_restore_state(cs, GETPC(), false); |
230 | return env->pc; |
231 | |
232 | case TO_SPR(0, 17): /* SR */ |
233 | return cpu_get_sr(env); |
234 | |
235 | case TO_SPR(0, 18): /* PPC */ |
236 | cpu_restore_state(cs, GETPC(), false); |
237 | return env->ppc; |
238 | |
239 | case TO_SPR(0, 32): /* EPCR */ |
240 | return env->epcr; |
241 | |
242 | case TO_SPR(0, 48): /* EEAR */ |
243 | return env->eear; |
244 | |
245 | case TO_SPR(0, 64): /* ESR */ |
246 | return env->esr; |
247 | |
248 | case TO_SPR(0, 128): /* COREID */ |
249 | return cpu->parent_obj.cpu_index; |
250 | |
251 | case TO_SPR(0, 129): /* NUMCORES */ |
252 | return ms->smp.max_cpus; |
253 | |
254 | case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */ |
255 | idx = (spr - 1024); |
256 | return env->shadow_gpr[idx / 32][idx % 32]; |
257 | |
258 | case TO_SPR(1, 512) ... TO_SPR(1, 512 + TLB_SIZE - 1): /* DTLBW0MR 0-127 */ |
259 | idx = spr - TO_SPR(1, 512); |
260 | return env->tlb.dtlb[idx].mr; |
261 | |
262 | case TO_SPR(1, 640) ... TO_SPR(1, 640 + TLB_SIZE - 1): /* DTLBW0TR 0-127 */ |
263 | idx = spr - TO_SPR(1, 640); |
264 | return env->tlb.dtlb[idx].tr; |
265 | |
266 | case TO_SPR(1, 768) ... TO_SPR(1, 895): /* DTLBW1MR 0-127 */ |
267 | case TO_SPR(1, 896) ... TO_SPR(1, 1023): /* DTLBW1TR 0-127 */ |
268 | case TO_SPR(1, 1024) ... TO_SPR(1, 1151): /* DTLBW2MR 0-127 */ |
269 | case TO_SPR(1, 1152) ... TO_SPR(1, 1279): /* DTLBW2TR 0-127 */ |
270 | case TO_SPR(1, 1280) ... TO_SPR(1, 1407): /* DTLBW3MR 0-127 */ |
271 | case TO_SPR(1, 1408) ... TO_SPR(1, 1535): /* DTLBW3TR 0-127 */ |
272 | break; |
273 | |
274 | case TO_SPR(2, 512) ... TO_SPR(2, 512 + TLB_SIZE - 1): /* ITLBW0MR 0-127 */ |
275 | idx = spr - TO_SPR(2, 512); |
276 | return env->tlb.itlb[idx].mr; |
277 | |
278 | case TO_SPR(2, 640) ... TO_SPR(2, 640 + TLB_SIZE - 1): /* ITLBW0TR 0-127 */ |
279 | idx = spr - TO_SPR(2, 640); |
280 | return env->tlb.itlb[idx].tr; |
281 | |
282 | case TO_SPR(2, 768) ... TO_SPR(2, 895): /* ITLBW1MR 0-127 */ |
283 | case TO_SPR(2, 896) ... TO_SPR(2, 1023): /* ITLBW1TR 0-127 */ |
284 | case TO_SPR(2, 1024) ... TO_SPR(2, 1151): /* ITLBW2MR 0-127 */ |
285 | case TO_SPR(2, 1152) ... TO_SPR(2, 1279): /* ITLBW2TR 0-127 */ |
286 | case TO_SPR(2, 1280) ... TO_SPR(2, 1407): /* ITLBW3MR 0-127 */ |
287 | case TO_SPR(2, 1408) ... TO_SPR(2, 1535): /* ITLBW3TR 0-127 */ |
288 | break; |
289 | |
290 | case TO_SPR(5, 1): /* MACLO */ |
291 | return (uint32_t)env->mac; |
292 | break; |
293 | case TO_SPR(5, 2): /* MACHI */ |
294 | return env->mac >> 32; |
295 | break; |
296 | |
297 | case TO_SPR(8, 0): /* PMR */ |
298 | return env->pmr; |
299 | |
300 | case TO_SPR(9, 0): /* PICMR */ |
301 | return env->picmr; |
302 | |
303 | case TO_SPR(9, 2): /* PICSR */ |
304 | return env->picsr; |
305 | |
306 | case TO_SPR(10, 0): /* TTMR */ |
307 | return env->ttmr; |
308 | |
309 | case TO_SPR(10, 1): /* TTCR */ |
310 | cpu_openrisc_count_update(cpu); |
311 | return cpu_openrisc_count_get(cpu); |
312 | #endif |
313 | |
314 | case TO_SPR(0, 20): /* FPCSR */ |
315 | return env->fpcsr; |
316 | } |
317 | |
318 | /* for rd is passed in, if rd unchanged, just keep it back. */ |
319 | return rd; |
320 | } |
321 | |