master
c 359 lines 9.03 KB
Raw
1 /*
2 * MIPS emulation helpers for qemu.
3 *
4 * Copyright (c) 2004-2005 Jocelyn Mayer
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "internal.h"
24 #include "exec/helper-proto.h"
25 #include "exec/memop.h"
26 #include "fpu_helper.h"
27 #include "qemu/crc32c.h"
28 #include "qemu/timer.h"
29 #include <zlib.h>
30
31 static inline target_ulong bitswap(target_ulong v)
32 {
33 v = ((v >> 1) & (target_ulong)0x5555555555555555ULL) |
34 ((v & (target_ulong)0x5555555555555555ULL) << 1);
35 v = ((v >> 2) & (target_ulong)0x3333333333333333ULL) |
36 ((v & (target_ulong)0x3333333333333333ULL) << 2);
37 v = ((v >> 4) & (target_ulong)0x0F0F0F0F0F0F0F0FULL) |
38 ((v & (target_ulong)0x0F0F0F0F0F0F0F0FULL) << 4);
39 return v;
40 }
41
42 #ifdef TARGET_MIPS64
43 target_ulong helper_dbitswap(target_ulong rt)
44 {
45 return bitswap(rt);
46 }
47 #endif
48
49 target_ulong helper_bitswap(target_ulong rt)
50 {
51 return (int32_t)bitswap(rt);
52 }
53
54 target_ulong helper_rotx(target_ulong rs, uint32_t shift, uint32_t shiftx,
55 uint32_t stripe)
56 {
57 int i;
58 uint64_t tmp0 = ((uint64_t)rs) << 32 | ((uint64_t)rs & 0xffffffff);
59 uint64_t tmp1 = tmp0;
60 for (i = 0; i <= 46; i++) {
61 int s;
62 if (i & 0x8) {
63 s = shift;
64 } else {
65 s = shiftx;
66 }
67
68 if (stripe != 0 && !(i & 0x4)) {
69 s = ~s;
70 }
71 if (s & 0x10) {
72 if (tmp0 & (1LL << (i + 16))) {
73 tmp1 |= 1LL << i;
74 } else {
75 tmp1 &= ~(1LL << i);
76 }
77 }
78 }
79
80 uint64_t tmp2 = tmp1;
81 for (i = 0; i <= 38; i++) {
82 int s;
83 if (i & 0x4) {
84 s = shift;
85 } else {
86 s = shiftx;
87 }
88
89 if (s & 0x8) {
90 if (tmp1 & (1LL << (i + 8))) {
91 tmp2 |= 1LL << i;
92 } else {
93 tmp2 &= ~(1LL << i);
94 }
95 }
96 }
97
98 uint64_t tmp3 = tmp2;
99 for (i = 0; i <= 34; i++) {
100 int s;
101 if (i & 0x2) {
102 s = shift;
103 } else {
104 s = shiftx;
105 }
106 if (s & 0x4) {
107 if (tmp2 & (1LL << (i + 4))) {
108 tmp3 |= 1LL << i;
109 } else {
110 tmp3 &= ~(1LL << i);
111 }
112 }
113 }
114
115 uint64_t tmp4 = tmp3;
116 for (i = 0; i <= 32; i++) {
117 int s;
118 if (i & 0x1) {
119 s = shift;
120 } else {
121 s = shiftx;
122 }
123 if (s & 0x2) {
124 if (tmp3 & (1LL << (i + 2))) {
125 tmp4 |= 1LL << i;
126 } else {
127 tmp4 &= ~(1LL << i);
128 }
129 }
130 }
131
132 uint64_t tmp5 = tmp4;
133 for (i = 0; i <= 31; i++) {
134 int s;
135 s = shift;
136 if (s & 0x1) {
137 if (tmp4 & (1LL << (i + 1))) {
138 tmp5 |= 1LL << i;
139 } else {
140 tmp5 &= ~(1LL << i);
141 }
142 }
143 }
144
145 return (int64_t)(int32_t)(uint32_t)tmp5;
146 }
147
148 /* these crc32 functions are based on target/loongarch/tcg/op_helper.c */
149 target_ulong helper_crc32(target_ulong val, target_ulong m, uint32_t sz)
150 {
151 uint8_t buf[8];
152 target_ulong mask = ((sz * 8) == 64) ?
153 (target_ulong) -1ULL :
154 ((1ULL << (sz * 8)) - 1);
155
156 m &= mask;
157 stq_le_p(buf, m);
158 return (int32_t) (crc32(val ^ 0xffffffff, buf, sz) ^ 0xffffffff);
159 }
160
161 target_ulong helper_crc32c(target_ulong val, target_ulong m, uint32_t sz)
162 {
163 uint8_t buf[8];
164 target_ulong mask = ((sz * 8) == 64) ?
165 (target_ulong) -1ULL :
166 ((1ULL << (sz * 8)) - 1);
167 m &= mask;
168 stq_le_p(buf, m);
169 return (int32_t) (crc32c(val, buf, sz) ^ 0xffffffff);
170 }
171
172 void helper_fork(target_ulong arg1, target_ulong arg2)
173 {
174 /*
175 * arg1 = rt, arg2 = rs
176 * TODO: store to TC register
177 */
178 }
179
180 target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
181 {
182 target_long arg1 = arg;
183
184 if (arg1 < 0) {
185 /* No scheduling policy implemented. */
186 if (arg1 != -2) {
187 if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
188 env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
189 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
190 env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
191 do_raise_exception(env, EXCP_THREAD, GETPC());
192 }
193 }
194 } else if (arg1 == 0) {
195 if (0) {
196 /* TODO: TC underflow */
197 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
198 do_raise_exception(env, EXCP_THREAD, GETPC());
199 } else {
200 /* TODO: Deallocate TC */
201 }
202 } else if (arg1 > 0) {
203 /* Yield qualifier inputs not implemented. */
204 env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
205 env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
206 do_raise_exception(env, EXCP_THREAD, GETPC());
207 }
208 return env->CP0_YQMask;
209 }
210
211 static inline void check_hwrena(CPUMIPSState *env, int reg, uintptr_t pc)
212 {
213 if ((env->hflags & MIPS_HFLAG_CP0) || (env->CP0_HWREna & (1u << reg))) {
214 return;
215 }
216 do_raise_exception(env, EXCP_RI, pc);
217 }
218
219 target_ulong helper_rdhwr_cpunum(CPUMIPSState *env)
220 {
221 check_hwrena(env, 0, GETPC());
222 return env->CP0_EBase & 0x3ff;
223 }
224
225 target_ulong helper_rdhwr_synci_step(CPUMIPSState *env)
226 {
227 check_hwrena(env, 1, GETPC());
228 return env->SYNCI_Step;
229 }
230
231 target_ulong helper_rdhwr_cc(CPUMIPSState *env)
232 {
233 check_hwrena(env, 2, GETPC());
234 #ifdef CONFIG_USER_ONLY
235 return env->CP0_Count;
236 #else
237 return (int32_t)cpu_mips_get_count(env);
238 #endif
239 }
240
241 target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
242 {
243 check_hwrena(env, 3, GETPC());
244 return env->CCRes;
245 }
246
247 target_ulong helper_rdhwr_performance(CPUMIPSState *env)
248 {
249 check_hwrena(env, 4, GETPC());
250 return env->CP0_Performance0;
251 }
252
253 target_ulong helper_rdhwr_xnp(CPUMIPSState *env)
254 {
255 check_hwrena(env, 5, GETPC());
256 return (env->CP0_Config5 >> CP0C5_XNP) & 1;
257 }
258
259 target_ulong helper_rdhwr_chord(CPUMIPSState *env)
260 {
261 check_hwrena(env, 30, GETPC());
262 return env->octeon_crypto.chord;
263 }
264
265 target_ulong helper_rdhwr_cvmcount(CPUMIPSState *env)
266 {
267 check_hwrena(env, 31, GETPC());
268 #ifdef CONFIG_USER_ONLY
269 return cpu_get_host_ticks();
270 #else
271 return (uint32_t)cpu_mips_get_count(env);
272 #endif
273 }
274
275 void helper_pmon(CPUMIPSState *env, int function)
276 {
277 function /= 2;
278 switch (function) {
279 case 2: /* TODO: char inbyte(int waitflag); */
280 if (env->active_tc.gpr[4] == 0) {
281 env->active_tc.gpr[2] = -1;
282 }
283 /* Fall through */
284 case 11: /* TODO: char inbyte (void); */
285 env->active_tc.gpr[2] = -1;
286 break;
287 case 3:
288 case 12:
289 printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
290 break;
291 case 17:
292 break;
293 case 158:
294 {
295 unsigned char *fmt = (void *)(uintptr_t)env->active_tc.gpr[4];
296 printf("%s", fmt);
297 }
298 break;
299 }
300 }
301
302 #ifdef TARGET_MIPS64
303 target_ulong helper_lcsr_cpucfg(CPUMIPSState *env, target_ulong rs)
304 {
305 switch (rs) {
306 case 0:
307 return env->CP0_PRid;
308 case 1:
309 return env->lcsr_cpucfg1;
310 case 2:
311 return env->lcsr_cpucfg2;
312 default:
313 return 0;
314 }
315 }
316 #endif
317
318 #if !defined(CONFIG_USER_ONLY)
319
320 void mips_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
321 MMUAccessType access_type,
322 int mmu_idx, uintptr_t retaddr)
323 {
324 CPUMIPSState *env = cpu_env(cs);
325 int error_code = 0;
326 int excp;
327
328 if (!(env->hflags & MIPS_HFLAG_DM)) {
329 env->CP0_BadVAddr = addr;
330 }
331
332 if (access_type == MMU_DATA_STORE) {
333 excp = EXCP_AdES;
334 } else {
335 excp = EXCP_AdEL;
336 if (access_type == MMU_INST_FETCH) {
337 error_code |= EXCP_INST_NOTAVAIL;
338 }
339 }
340
341 do_raise_exception_err(env, excp, error_code, retaddr);
342 }
343
344 void mips_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr,
345 vaddr addr, unsigned size,
346 MMUAccessType access_type,
347 int mmu_idx, MemTxAttrs attrs,
348 MemTxResult response, uintptr_t retaddr)
349 {
350 MIPSCPUClass *mcc = MIPS_CPU_GET_CLASS(cs);
351 CPUMIPSState *env = cpu_env(cs);
352
353 if (access_type == MMU_INST_FETCH) {
354 do_raise_exception(env, EXCP_IBE, retaddr);
355 } else if (!mcc->no_data_aborts) {
356 do_raise_exception(env, EXCP_DBE, retaddr);
357 }
358 }
359 #endif /* !CONFIG_USER_ONLY */