]> git.proxmox.com Git - mirror_qemu.git/blame - target/cris/op_helper.c
target/riscv: add riscv_cpu_get_name()
[mirror_qemu.git] / target / cris / op_helper.c
CommitLineData
81fdc5f8
TS
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
bf1b52d1 10 * version 2.1 of the License, or (at your option) any later version.
81fdc5f8
TS
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
8167ee88 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
81fdc5f8
TS
19 */
20
23b0d7df 21#include "qemu/osdep.h"
3e457172 22#include "cpu.h"
786c02f1 23#include "mmu.h"
2ef6175a 24#include "exec/helper-proto.h"
1de7afc9 25#include "qemu/host-utils.h"
63c91552 26#include "exec/exec-all.h"
81fdc5f8 27
d12d51d5
AL
28//#define CRIS_OP_HELPER_DEBUG
29
30
31#ifdef CRIS_OP_HELPER_DEBUG
32#define D(x) x
3f668b6c 33#define D_LOG(...) qemu_log(__VA_ARGS__)
d12d51d5 34#else
e2eef170 35#define D(x)
d12d51d5
AL
36#define D_LOG(...) do { } while (0)
37#endif
e2eef170 38
febc9920 39void helper_raise_exception(CPUCRISState *env, uint32_t index)
786c02f1 40{
dbefca23 41 CPUState *cs = env_cpu(env);
27103424
AF
42
43 cs->exception_index = index;
5638d180 44 cpu_loop_exit(cs);
786c02f1
EI
45}
46
febc9920 47void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid)
cf1d97f0
EI
48{
49#if !defined(CONFIG_USER_ONLY)
ac4df09f
RH
50 pid &= 0xff;
51 if (pid != (env->pregs[PR_PID] & 0xff)) {
52 cris_mmu_flush_pid(env, env->pregs[PR_PID]);
53 }
cf1d97f0
EI
54#endif
55}
56
febc9920 57void helper_spc_write(CPUCRISState *env, uint32_t new_spc)
a1aebcb8
EI
58{
59#if !defined(CONFIG_USER_ONLY)
dbefca23 60 CPUState *cs = env_cpu(env);
31b030d4
AF
61
62 tlb_flush_page(cs, env->pregs[PR_SPC]);
63 tlb_flush_page(cs, new_spc);
a1aebcb8
EI
64#endif
65}
66
cf1d97f0 67/* Used by the tlb decoder. */
ac4df09f
RH
68#define EXTRACT_FIELD(src, start, end) \
69 (((src) >> start) & ((1 << (end - start + 1)) - 1))
cf1d97f0 70
febc9920 71void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg)
dceaf394 72{
ac4df09f
RH
73 uint32_t srs;
74 srs = env->pregs[PR_SRS];
75 srs &= 3;
76 env->sregs[srs][sreg] = env->regs[reg];
dceaf394
EI
77
78#if !defined(CONFIG_USER_ONLY)
ac4df09f
RH
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) {
dbefca23 110 tlb_flush_page(env_cpu(env), vaddr);
ac4df09f
RH
111 }
112 }
113 }
dceaf394
EI
114#endif
115}
116
febc9920 117void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg)
dceaf394 118{
ac4df09f
RH
119 uint32_t srs;
120 env->pregs[PR_SRS] &= 3;
121 srs = env->pregs[PR_SRS];
122
dceaf394 123#if !defined(CONFIG_USER_ONLY)
ac4df09f
RH
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 }
dceaf394 140#endif
ac4df09f 141 env->regs[reg] = env->sregs[srs][sreg];
dceaf394
EI
142}
143
a1170bfd 144static void cris_ccs_rshift(CPUCRISState *env)
dceaf394 145{
ac4df09f
RH
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;
dceaf394
EI
158}
159
febc9920 160void helper_rfe(CPUCRISState *env)
b41f7df0 161{
ac4df09f 162 int rflag = env->pregs[PR_CCS] & R_FLAG;
bf443337 163
ac4df09f
RH
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);
dceaf394 168
ac4df09f 169 cris_ccs_rshift(env);
dceaf394 170
ac4df09f
RH
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 }
b41f7df0
EI
175}
176
febc9920 177void helper_rfn(CPUCRISState *env)
5bf8f1ab 178{
ac4df09f 179 int rflag = env->pregs[PR_CCS] & R_FLAG;
5bf8f1ab 180
ac4df09f
RH
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);
5bf8f1ab 185
ac4df09f 186 cris_ccs_rshift(env);
5bf8f1ab 187
ac4df09f
RH
188 /* Set the P_FLAG only if the R_FLAG is not set. */
189 if (!rflag) {
190 env->pregs[PR_CCS] |= P_FLAG;
191 }
5bf8f1ab 192
ac4df09f
RH
193 /* Always set the M flag. */
194 env->pregs[PR_CCS] |= M_FLAG_V32;
5bf8f1ab
EI
195}
196
febc9920 197uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs)
abd5c94e 198{
ac4df09f
RH
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;
abd5c94e
EI
226}
227
febc9920
AJ
228static inline uint32_t evaluate_flags_writeback(CPUCRISState *env,
229 uint32_t flags, uint32_t ccs)
b41f7df0 230{
ac4df09f
RH
231 unsigned int x, z, mask;
232
8b81968c 233 /* Extended arithmetic, leave the z flag alone. */
ac4df09f
RH
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;
b41f7df0
EI
246}
247
febc9920
AJ
248uint32_t helper_evaluate_flags_muls(CPUCRISState *env,
249 uint32_t ccs, uint32_t res, uint32_t mof)
b41f7df0 250{
ac4df09f
RH
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);
b41f7df0
EI
269}
270
febc9920
AJ
271uint32_t helper_evaluate_flags_mulu(CPUCRISState *env,
272 uint32_t ccs, uint32_t res, uint32_t mof)
b41f7df0 273{
ac4df09f
RH
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);
b41f7df0
EI
290}
291
febc9920 292uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs,
6231868b 293 uint32_t src, uint32_t dst, uint32_t res)
b41f7df0 294{
ac4df09f
RH
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);
b41f7df0
EI
320}
321
febc9920 322uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs,
6231868b 323 uint32_t src, uint32_t dst, uint32_t res)
b41f7df0 324{
ac4df09f
RH
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);
a8cf66bb
EI
350}
351
febc9920 352uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs,
6231868b 353 uint32_t src, uint32_t dst, uint32_t res)
a8cf66bb 354{
ac4df09f
RH
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);
b41f7df0
EI
381}
382
febc9920
AJ
383uint32_t helper_evaluate_flags_move_4(CPUCRISState *env,
384 uint32_t ccs, uint32_t res)
b41f7df0 385{
ac4df09f 386 uint32_t flags = 0;
b41f7df0 387
ac4df09f
RH
388 if ((int32_t)res < 0) {
389 flags |= N_FLAG;
390 } else if (res == 0L) {
391 flags |= Z_FLAG;
392 }
b41f7df0 393
ac4df09f 394 return evaluate_flags_writeback(env, flags, ccs);
b41f7df0 395}
ac4df09f 396
febc9920
AJ
397uint32_t helper_evaluate_flags_move_2(CPUCRISState *env,
398 uint32_t ccs, uint32_t res)
b41f7df0 399{
ac4df09f 400 uint32_t flags = 0;
b41f7df0 401
ac4df09f
RH
402 if ((int16_t)res < 0L) {
403 flags |= N_FLAG;
404 } else if (res == 0) {
405 flags |= Z_FLAG;
406 }
b41f7df0 407
ac4df09f 408 return evaluate_flags_writeback(env, flags, ccs);
b41f7df0
EI
409}
410
ac4df09f
RH
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 */
febc9920 415void helper_evaluate_flags(CPUCRISState *env)
b41f7df0 416{
ac4df09f
RH
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]);
b41f7df0 504}
30abcfc7 505
febc9920 506void helper_top_evaluate_flags(CPUCRISState *env)
30abcfc7 507{
ac4df09f
RH
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 }
30abcfc7 580}