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