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