1 /*
2 * CRIS helper routines
3 *
4 * Copyright (c) 2007 AXIS Communications
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.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 "mmu.h"
24 #include "exec/helper-proto.h"
25 #include "qemu/host-utils.h"
26 #include "exec/exec-all.h"
27
28 //#define CRIS_OP_HELPER_DEBUG
29
30
31 #ifdef CRIS_OP_HELPER_DEBUG
32 #define D(x) x
33 #define D_LOG(...) qemu_log(__VA_ARGS__)
34 #else
35 #define D(x)
36 #define D_LOG(...) do { } while (0)
37 #endif
38
helper_raise_exception(CPUCRISState * env,uint32_t index)39 void helper_raise_exception(CPUCRISState *env, uint32_t index)
40 {
41 CPUState *cs = env_cpu(env);
42
43 cs->exception_index = index;
44 cpu_loop_exit(cs);
45 }
46
helper_tlb_flush_pid(CPUCRISState * env,uint32_t pid)47 void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid)
48 {
49 #if !defined(CONFIG_USER_ONLY)
50 pid &= 0xff;
51 if (pid != (env->pregs[PR_PID] & 0xff)) {
52 cris_mmu_flush_pid(env, env->pregs[PR_PID]);
53 }
54 #endif
55 }
56
helper_spc_write(CPUCRISState * env,uint32_t new_spc)57 void helper_spc_write(CPUCRISState *env, uint32_t new_spc)
58 {
59 #if !defined(CONFIG_USER_ONLY)
60 CPUState *cs = env_cpu(env);
61
62 tlb_flush_page(cs, env->pregs[PR_SPC]);
63 tlb_flush_page(cs, new_spc);
64 #endif
65 }
66
67 /* Used by the tlb decoder. */
68 #define EXTRACT_FIELD(src, start, end) \
69 (((src) >> start) & ((1 << (end - start + 1)) - 1))
70
helper_movl_sreg_reg(CPUCRISState * env,uint32_t sreg,uint32_t reg)71 void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg)
72 {
73 uint32_t srs;
74 srs = env->pregs[PR_SRS];
75 srs &= 3;
76 env->sregs[srs][sreg] = env->regs[reg];
77
78 #if !defined(CONFIG_USER_ONLY)
79 if (srs == 1 || srs == 2) {
80 if (sreg == 6) {
81 /* Writes to tlb-hi write to mm_cause as a side effect. */
82 env->sregs[SFR_RW_MM_TLB_HI] = env->regs[reg];
83 env->sregs[SFR_R_MM_CAUSE] = env->regs[reg];
84 } else if (sreg == 5) {
85 uint32_t set;
86 uint32_t idx;
87 uint32_t lo, hi;
88 uint32_t vaddr;
89 int tlb_v;
90
91 idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
92 set >>= 4;
93 set &= 3;
94
95 idx &= 15;
96 /* We've just made a write to tlb_lo. */
97 lo = env->sregs[SFR_RW_MM_TLB_LO];
98 /* Writes are done via r_mm_cause. */
99 hi = env->sregs[SFR_R_MM_CAUSE];
100
101 vaddr = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].hi, 13, 31);
102 vaddr <<= TARGET_PAGE_BITS;
103 tlb_v = EXTRACT_FIELD(env->tlbsets[srs - 1][set][idx].lo, 3, 3);
104 env->tlbsets[srs - 1][set][idx].lo = lo;
105 env->tlbsets[srs - 1][set][idx].hi = hi;
106
107 D_LOG("tlb flush vaddr=%x v=%d pc=%x\n",
108 vaddr, tlb_v, env->pc);
109 if (tlb_v) {
110 tlb_flush_page(env_cpu(env), vaddr);
111 }
112 }
113 }
114 #endif
115 }
116
helper_movl_reg_sreg(CPUCRISState * env,uint32_t reg,uint32_t sreg)117 void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg)
118 {
119 uint32_t srs;
120 env->pregs[PR_SRS] &= 3;
121 srs = env->pregs[PR_SRS];
122
123 #if !defined(CONFIG_USER_ONLY)
124 if (srs == 1 || srs == 2) {
125 uint32_t set;
126 uint32_t idx;
127 uint32_t lo, hi;
128
129 idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
130 set >>= 4;
131 set &= 3;
132 idx &= 15;
133
134 /* Update the mirror regs. */
135 hi = env->tlbsets[srs - 1][set][idx].hi;
136 lo = env->tlbsets[srs - 1][set][idx].lo;
137 env->sregs[SFR_RW_MM_TLB_HI] = hi;
138 env->sregs[SFR_RW_MM_TLB_LO] = lo;
139 }
140 #endif
141 env->regs[reg] = env->sregs[srs][sreg];
142 }
143
cris_ccs_rshift(CPUCRISState * env)144 static void cris_ccs_rshift(CPUCRISState *env)
145 {
146 uint32_t ccs;
147
148 /* Apply the ccs shift. */
149 ccs = env->pregs[PR_CCS];
150 ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10);
151 if (ccs & U_FLAG) {
152 /* Enter user mode. */
153 env->ksp = env->regs[R_SP];
154 env->regs[R_SP] = env->pregs[PR_USP];
155 }
156
157 env->pregs[PR_CCS] = ccs;
158 }
159
helper_rfe(CPUCRISState * env)160 void helper_rfe(CPUCRISState *env)
161 {
162 int rflag = env->pregs[PR_CCS] & R_FLAG;
163
164 D_LOG("rfe: erp=%x pid=%x ccs=%x btarget=%x\n",
165 env->pregs[PR_ERP], env->pregs[PR_PID],
166 env->pregs[PR_CCS],
167 env->btarget);
168
169 cris_ccs_rshift(env);
170
171 /* RFE sets the P_FLAG only if the R_FLAG is not set. */
172 if (!rflag) {
173 env->pregs[PR_CCS] |= P_FLAG;
174 }
175 }
176
helper_rfn(CPUCRISState * env)177 void helper_rfn(CPUCRISState *env)
178 {
179 int rflag = env->pregs[PR_CCS] & R_FLAG;
180
181 D_LOG("rfn: erp=%x pid=%x ccs=%x btarget=%x\n",
182 env->pregs[PR_ERP], env->pregs[PR_PID],
183 env->pregs[PR_CCS],
184 env->btarget);
185
186 cris_ccs_rshift(env);
187
188 /* Set the P_FLAG only if the R_FLAG is not set. */
189 if (!rflag) {
190 env->pregs[PR_CCS] |= P_FLAG;
191 }
192
193 /* Always set the M flag. */
194 env->pregs[PR_CCS] |= M_FLAG_V32;
195 }
196
helper_btst(CPUCRISState * env,uint32_t t0,uint32_t t1,uint32_t ccs)197 uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs)
198 {
199 /* FIXME: clean this up. */
200
201 /*
202 * des ref:
203 * The N flag is set according to the selected bit in the dest reg.
204 * The Z flag is set if the selected bit and all bits to the right are
205 * zero.
206 * The X flag is cleared.
207 * Other flags are left untouched.
208 * The destination reg is not affected.
209 */
210 unsigned int fz, sbit, bset, mask, masked_t0;
211
212 sbit = t1 & 31;
213 bset = !!(t0 & (1 << sbit));
214 mask = sbit == 31 ? -1 : (1 << (sbit + 1)) - 1;
215 masked_t0 = t0 & mask;
216 fz = !(masked_t0 | bset);
217
218 /* Clear the X, N and Z flags. */
219 ccs = ccs & ~(X_FLAG | N_FLAG | Z_FLAG);
220 if (env->pregs[PR_VR] < 32) {
221 ccs &= ~(V_FLAG | C_FLAG);
222 }
223 /* Set the N and Z flags accordingly. */
224 ccs |= (bset << 3) | (fz << 2);
225 return ccs;
226 }
227
evaluate_flags_writeback(CPUCRISState * env,uint32_t flags,uint32_t ccs)228 static inline uint32_t evaluate_flags_writeback(CPUCRISState *env,
229 uint32_t flags, uint32_t ccs)
230 {
231 unsigned int x, z, mask;
232
233 /* Extended arithmetic, leave the z flag alone. */
234 x = env->cc_x;
235 mask = env->cc_mask | X_FLAG;
236 if (x) {
237 z = flags & Z_FLAG;
238 mask = mask & ~z;
239 }
240 flags &= mask;
241
242 /* all insn clear the x-flag except setf or clrf. */
243 ccs &= ~mask;
244 ccs |= flags;
245 return ccs;
246 }
247
helper_evaluate_flags_muls(CPUCRISState * env,uint32_t ccs,uint32_t res,uint32_t mof)248 uint32_t helper_evaluate_flags_muls(CPUCRISState *env,
249 uint32_t ccs, uint32_t res, uint32_t mof)
250 {
251 uint32_t flags = 0;
252 int64_t tmp;
253 int dneg;
254
255 dneg = ((int32_t)res) < 0;
256
257 tmp = mof;
258 tmp <<= 32;
259 tmp |= res;
260 if (tmp == 0) {
261 flags |= Z_FLAG;
262 } else if (tmp < 0) {
263 flags |= N_FLAG;
264 }
265 if ((dneg && mof != -1) || (!dneg && mof != 0)) {
266 flags |= V_FLAG;
267 }
268 return evaluate_flags_writeback(env, flags, ccs);
269 }
270
helper_evaluate_flags_mulu(CPUCRISState * env,uint32_t ccs,uint32_t res,uint32_t mof)271 uint32_t helper_evaluate_flags_mulu(CPUCRISState *env,
272 uint32_t ccs, uint32_t res, uint32_t mof)
273 {
274 uint32_t flags = 0;
275 uint64_t tmp;
276
277 tmp = mof;
278 tmp <<= 32;
279 tmp |= res;
280 if (tmp == 0) {
281 flags |= Z_FLAG;
282 } else if (tmp >> 63) {
283 flags |= N_FLAG;
284 }
285 if (mof) {
286 flags |= V_FLAG;
287 }
288
289 return evaluate_flags_writeback(env, flags, ccs);
290 }
291
helper_evaluate_flags_mcp(CPUCRISState * env,uint32_t ccs,uint32_t src,uint32_t dst,uint32_t res)292 uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs,
293 uint32_t src, uint32_t dst, uint32_t res)
294 {
295 uint32_t flags = 0;
296
297 src = src & 0x80000000;
298 dst = dst & 0x80000000;
299
300 if ((res & 0x80000000L) != 0L) {
301 flags |= N_FLAG;
302 if (!src && !dst) {
303 flags |= V_FLAG;
304 } else if (src & dst) {
305 flags |= R_FLAG;
306 }
307 } else {
308 if (res == 0L) {
309 flags |= Z_FLAG;
310 }
311 if (src & dst) {
312 flags |= V_FLAG;
313 }
314 if (dst | src) {
315 flags |= R_FLAG;
316 }
317 }
318
319 return evaluate_flags_writeback(env, flags, ccs);
320 }
321
helper_evaluate_flags_alu_4(CPUCRISState * env,uint32_t ccs,uint32_t src,uint32_t dst,uint32_t res)322 uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs,
323 uint32_t src, uint32_t dst, uint32_t res)
324 {
325 uint32_t flags = 0;
326
327 src = src & 0x80000000;
328 dst = dst & 0x80000000;
329
330 if ((res & 0x80000000L) != 0L) {
331 flags |= N_FLAG;
332 if (!src && !dst) {
333 flags |= V_FLAG;
334 } else if (src & dst) {
335 flags |= C_FLAG;
336 }
337 } else {
338 if (res == 0L) {
339 flags |= Z_FLAG;
340 }
341 if (src & dst) {
342 flags |= V_FLAG;
343 }
344 if (dst | src) {
345 flags |= C_FLAG;
346 }
347 }
348
349 return evaluate_flags_writeback(env, flags, ccs);
350 }
351
helper_evaluate_flags_sub_4(CPUCRISState * env,uint32_t ccs,uint32_t src,uint32_t dst,uint32_t res)352 uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs,
353 uint32_t src, uint32_t dst, uint32_t res)
354 {
355 uint32_t flags = 0;
356
357 src = (~src) & 0x80000000;
358 dst = dst & 0x80000000;
359
360 if ((res & 0x80000000L) != 0L) {
361 flags |= N_FLAG;
362 if (!src && !dst) {
363 flags |= V_FLAG;
364 } else if (src & dst) {
365 flags |= C_FLAG;
366 }
367 } else {
368 if (res == 0L) {
369 flags |= Z_FLAG;
370 }
371 if (src & dst) {
372 flags |= V_FLAG;
373 }
374 if (dst | src) {
375 flags |= C_FLAG;
376 }
377 }
378
379 flags ^= C_FLAG;
380 return evaluate_flags_writeback(env, flags, ccs);
381 }
382
helper_evaluate_flags_move_4(CPUCRISState * env,uint32_t ccs,uint32_t res)383 uint32_t helper_evaluate_flags_move_4(CPUCRISState *env,
384 uint32_t ccs, uint32_t res)
385 {
386 uint32_t flags = 0;
387
388 if ((int32_t)res < 0) {
389 flags |= N_FLAG;
390 } else if (res == 0L) {
391 flags |= Z_FLAG;
392 }
393
394 return evaluate_flags_writeback(env, flags, ccs);
395 }
396
helper_evaluate_flags_move_2(CPUCRISState * env,uint32_t ccs,uint32_t res)397 uint32_t helper_evaluate_flags_move_2(CPUCRISState *env,
398 uint32_t ccs, uint32_t res)
399 {
400 uint32_t flags = 0;
401
402 if ((int16_t)res < 0L) {
403 flags |= N_FLAG;
404 } else if (res == 0) {
405 flags |= Z_FLAG;
406 }
407
408 return evaluate_flags_writeback(env, flags, ccs);
409 }
410
411 /*
412 * TODO: This is expensive. We could split things up and only evaluate part of
413 * CCR on a need to know basis. For now, we simply re-evaluate everything.
414 */
helper_evaluate_flags(CPUCRISState * env)415 void helper_evaluate_flags(CPUCRISState *env)
416 {
417 uint32_t src, dst, res;
418 uint32_t flags = 0;
419
420 src = env->cc_src;
421 dst = env->cc_dest;
422 res = env->cc_result;
423
424 if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) {
425 src = ~src;
426 }
427
428 /*
429 * Now, evaluate the flags. This stuff is based on
430 * Per Zander's CRISv10 simulator.
431 */
432 switch (env->cc_size) {
433 case 1:
434 if ((res & 0x80L) != 0L) {
435 flags |= N_FLAG;
436 if (((src & 0x80L) == 0L) && ((dst & 0x80L) == 0L)) {
437 flags |= V_FLAG;
438 } else if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) {
439 flags |= C_FLAG;
440 }
441 } else {
442 if ((res & 0xFFL) == 0L) {
443 flags |= Z_FLAG;
444 }
445 if (((src & 0x80L) != 0L) && ((dst & 0x80L) != 0L)) {
446 flags |= V_FLAG;
447 }
448 if ((dst & 0x80L) != 0L || (src & 0x80L) != 0L) {
449 flags |= C_FLAG;
450 }
451 }
452 break;
453 case 2:
454 if ((res & 0x8000L) != 0L) {
455 flags |= N_FLAG;
456 if (((src & 0x8000L) == 0L) && ((dst & 0x8000L) == 0L)) {
457 flags |= V_FLAG;
458 } else if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) {
459 flags |= C_FLAG;
460 }
461 } else {
462 if ((res & 0xFFFFL) == 0L) {
463 flags |= Z_FLAG;
464 }
465 if (((src & 0x8000L) != 0L) && ((dst & 0x8000L) != 0L)) {
466 flags |= V_FLAG;
467 }
468 if ((dst & 0x8000L) != 0L || (src & 0x8000L) != 0L) {
469 flags |= C_FLAG;
470 }
471 }
472 break;
473 case 4:
474 if ((res & 0x80000000L) != 0L) {
475 flags |= N_FLAG;
476 if (((src & 0x80000000L) == 0L) && ((dst & 0x80000000L) == 0L)) {
477 flags |= V_FLAG;
478 } else if (((src & 0x80000000L) != 0L) &&
479 ((dst & 0x80000000L) != 0L)) {
480 flags |= C_FLAG;
481 }
482 } else {
483 if (res == 0L) {
484 flags |= Z_FLAG;
485 }
486 if (((src & 0x80000000L) != 0L) && ((dst & 0x80000000L) != 0L)) {
487 flags |= V_FLAG;
488 }
489 if ((dst & 0x80000000L) != 0L || (src & 0x80000000L) != 0L) {
490 flags |= C_FLAG;
491 }
492 }
493 break;
494 default:
495 break;
496 }
497
498 if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) {
499 flags ^= C_FLAG;
500 }
501
502 env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags,
503 env->pregs[PR_CCS]);
504 }
505
helper_top_evaluate_flags(CPUCRISState * env)506 void helper_top_evaluate_flags(CPUCRISState *env)
507 {
508 switch (env->cc_op) {
509 case CC_OP_MCP:
510 env->pregs[PR_CCS]
511 = helper_evaluate_flags_mcp(env, env->pregs[PR_CCS],
512 env->cc_src, env->cc_dest,
513 env->cc_result);
514 break;
515 case CC_OP_MULS:
516 env->pregs[PR_CCS]
517 = helper_evaluate_flags_muls(env, env->pregs[PR_CCS],
518 env->cc_result, env->pregs[PR_MOF]);
519 break;
520 case CC_OP_MULU:
521 env->pregs[PR_CCS]
522 = helper_evaluate_flags_mulu(env, env->pregs[PR_CCS],
523 env->cc_result, env->pregs[PR_MOF]);
524 break;
525 case CC_OP_MOVE:
526 case CC_OP_AND:
527 case CC_OP_OR:
528 case CC_OP_XOR:
529 case CC_OP_ASR:
530 case CC_OP_LSR:
531 case CC_OP_LSL:
532 switch (env->cc_size) {
533 case 4:
534 env->pregs[PR_CCS] =
535 helper_evaluate_flags_move_4(env,
536 env->pregs[PR_CCS],
537 env->cc_result);
538 break;
539 case 2:
540 env->pregs[PR_CCS] =
541 helper_evaluate_flags_move_2(env,
542 env->pregs[PR_CCS],
543 env->cc_result);
544 break;
545 default:
546 helper_evaluate_flags(env);
547 break;
548 }
549 break;
550 case CC_OP_FLAGS:
551 /* live. */
552 break;
553 case CC_OP_SUB:
554 case CC_OP_CMP:
555 if (env->cc_size == 4) {
556 env->pregs[PR_CCS] =
557 helper_evaluate_flags_sub_4(env,
558 env->pregs[PR_CCS],
559 env->cc_src, env->cc_dest,
560 env->cc_result);
561 } else {
562 helper_evaluate_flags(env);
563 }
564 break;
565 default:
566 switch (env->cc_size) {
567 case 4:
568 env->pregs[PR_CCS] =
569 helper_evaluate_flags_alu_4(env,
570 env->pregs[PR_CCS],
571 env->cc_src, env->cc_dest,
572 env->cc_result);
573 break;
574 default:
575 helper_evaluate_flags(env);
576 break;
577 }
578 break;
579 }
580 }
581