]> git.proxmox.com Git - mirror_qemu.git/blame - target-mips/op.c
update
[mirror_qemu.git] / target-mips / op.c
CommitLineData
6af0bf9c
FB
1/*
2 * MIPS emulation micro-operations 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 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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "config.h"
22#include "exec.h"
23
1b351e52
FB
24#ifndef CALL_FROM_TB0
25#define CALL_FROM_TB0(func) func();
26#endif
27#ifndef CALL_FROM_TB1
28#define CALL_FROM_TB1(func, arg0) func(arg0);
29#endif
30#ifndef CALL_FROM_TB1_CONST16
31#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0);
32#endif
33#ifndef CALL_FROM_TB2
34#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1);
35#endif
36#ifndef CALL_FROM_TB2_CONST16
37#define CALL_FROM_TB2_CONST16(func, arg0, arg1) \
38CALL_FROM_TB2(func, arg0, arg1);
39#endif
40#ifndef CALL_FROM_TB3
41#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2);
42#endif
43#ifndef CALL_FROM_TB4
44#define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
45 func(arg0, arg1, arg2, arg3);
46#endif
47
6af0bf9c
FB
48#define REG 1
49#include "op_template.c"
50#undef REG
51#define REG 2
52#include "op_template.c"
53#undef REG
54#define REG 3
55#include "op_template.c"
56#undef REG
57#define REG 4
58#include "op_template.c"
59#undef REG
60#define REG 5
61#include "op_template.c"
62#undef REG
63#define REG 6
64#include "op_template.c"
65#undef REG
66#define REG 7
67#include "op_template.c"
68#undef REG
69#define REG 8
70#include "op_template.c"
71#undef REG
72#define REG 9
73#include "op_template.c"
74#undef REG
75#define REG 10
76#include "op_template.c"
77#undef REG
78#define REG 11
79#include "op_template.c"
80#undef REG
81#define REG 12
82#include "op_template.c"
83#undef REG
84#define REG 13
85#include "op_template.c"
86#undef REG
87#define REG 14
88#include "op_template.c"
89#undef REG
90#define REG 15
91#include "op_template.c"
92#undef REG
93#define REG 16
94#include "op_template.c"
95#undef REG
96#define REG 17
97#include "op_template.c"
98#undef REG
99#define REG 18
100#include "op_template.c"
101#undef REG
102#define REG 19
103#include "op_template.c"
104#undef REG
105#define REG 20
106#include "op_template.c"
107#undef REG
108#define REG 21
109#include "op_template.c"
110#undef REG
111#define REG 22
112#include "op_template.c"
113#undef REG
114#define REG 23
115#include "op_template.c"
116#undef REG
117#define REG 24
118#include "op_template.c"
119#undef REG
120#define REG 25
121#include "op_template.c"
122#undef REG
123#define REG 26
124#include "op_template.c"
125#undef REG
126#define REG 27
127#include "op_template.c"
128#undef REG
129#define REG 28
130#include "op_template.c"
131#undef REG
132#define REG 29
133#include "op_template.c"
134#undef REG
135#define REG 30
136#include "op_template.c"
137#undef REG
138#define REG 31
139#include "op_template.c"
140#undef REG
141
142#define TN T0
143#include "op_template.c"
144#undef TN
145#define TN T1
146#include "op_template.c"
147#undef TN
148#define TN T2
149#include "op_template.c"
150#undef TN
151
152void op_dup_T0 (void)
153{
154 T2 = T0;
155 RETURN();
156}
157
158void op_load_HI (void)
159{
160 T0 = env->HI;
161 RETURN();
162}
163
164void op_store_HI (void)
165{
166 env->HI = T0;
167 RETURN();
168}
169
170void op_load_LO (void)
171{
172 T0 = env->LO;
173 RETURN();
174}
175
176void op_store_LO (void)
177{
178 env->LO = T0;
179 RETURN();
180}
181
182/* Load and store */
183#define MEMSUFFIX _raw
184#include "op_mem.c"
185#undef MEMSUFFIX
186#if !defined(CONFIG_USER_ONLY)
187#define MEMSUFFIX _user
188#include "op_mem.c"
189#undef MEMSUFFIX
190
191#define MEMSUFFIX _kernel
192#include "op_mem.c"
193#undef MEMSUFFIX
194#endif
195
196/* Arithmetic */
197void op_add (void)
198{
199 T0 += T1;
200 RETURN();
201}
202
203void op_addo (void)
204{
205 target_ulong tmp;
206
207 tmp = T0;
208 T0 += T1;
209 if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) {
210 CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
211 }
212 RETURN();
213}
214
215void op_sub (void)
216{
217 T0 -= T1;
218 RETURN();
219}
220
221void op_subo (void)
222{
223 target_ulong tmp;
224
225 tmp = T0;
226 T0 = (int32_t)T0 - (int32_t)T1;
227 if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) {
228 CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
229 }
230 RETURN();
231}
232
233void op_mul (void)
234{
235 T0 = (int32_t)T0 * (int32_t)T1;
236 RETURN();
237}
238
239void op_div (void)
240{
241 if (T1 != 0) {
242 env->LO = (int32_t)T0 / (int32_t)T1;
243 env->HI = (int32_t)T0 % (int32_t)T1;
244 }
245 RETURN();
246}
247
248void op_divu (void)
249{
250 if (T1 != 0) {
251 env->LO = T0 / T1;
252 env->HI = T0 % T1;
253 }
254 RETURN();
255}
256
257/* Logical */
258void op_and (void)
259{
260 T0 &= T1;
261 RETURN();
262}
263
264void op_nor (void)
265{
266 T0 = ~(T0 | T1);
267 RETURN();
268}
269
270void op_or (void)
271{
272 T0 |= T1;
273 RETURN();
274}
275
276void op_xor (void)
277{
278 T0 ^= T1;
279 RETURN();
280}
281
282void op_sll (void)
283{
284 T0 = T0 << T1;
285 RETURN();
286}
287
288void op_sra (void)
289{
290 T0 = (int32_t)T0 >> T1;
291 RETURN();
292}
293
294void op_srl (void)
295{
296 T0 = T0 >> T1;
297 RETURN();
298}
299
300void op_sllv (void)
301{
302 T0 = T1 << (T0 & 0x1F);
303 RETURN();
304}
305
306void op_srav (void)
307{
308 T0 = (int32_t)T1 >> (T0 & 0x1F);
309 RETURN();
310}
311
312void op_srlv (void)
313{
314 T0 = T1 >> (T0 & 0x1F);
315 RETURN();
316}
317
318void op_clo (void)
319{
320 int n;
321
322 if (T0 == (target_ulong)-1) {
323 T0 = 32;
324 } else {
325 for (n = 0; n < 32; n++) {
326 if (!(T0 & (1 << 31)))
327 break;
328 T0 = T0 << 1;
329 }
330 T0 = n;
331 }
332 RETURN();
333}
334
335void op_clz (void)
336{
337 int n;
338
339 if (T0 == 0) {
340 T0 = 32;
341 } else {
342 for (n = 0; n < 32; n++) {
343 if (T0 & (1 << 31))
344 break;
345 T0 = T0 << 1;
346 }
347 T0 = n;
348 }
349 RETURN();
350}
351
352/* 64 bits arithmetic */
353#if (HOST_LONG_BITS == 64)
354static inline uint64_t get_HILO (void)
355{
356 return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
357}
358
359static inline void set_HILO (uint64_t HILO)
360{
361 env->LO = HILO & 0xFFFFFFFF;
362 env->HI = HILO >> 32;
363}
364
365void op_mult (void)
366{
367 set_HILO((int64_t)T0 * (int64_t)T1);
368 RETURN();
369}
370
371void op_multu (void)
372{
373 set_HILO((uint64_t)T0 * (uint64_t)T1);
374 RETURN();
375}
376
377void op_madd (void)
378{
379 int64_t tmp;
380
381 tmp = ((int64_t)T0 * (int64_t)T1);
382 set_HILO((int64_t)get_HILO() + tmp);
383 RETURN();
384}
385
386void op_maddu (void)
387{
388 uint64_t tmp;
389
390 tmp = ((uint64_t)T0 * (uint64_t)T1);
391 set_HILO(get_HILO() + tmp);
392 RETURN();
393}
394
395void op_msub (void)
396{
397 int64_t tmp;
398
399 tmp = ((int64_t)T0 * (int64_t)T1);
400 set_HILO((int64_t)get_HILO() - tmp);
401 RETURN();
402}
403
404void op_msubu (void)
405{
406 uint64_t tmp;
407
408 tmp = ((uint64_t)T0 * (uint64_t)T1);
409 set_HILO(get_HILO() - tmp);
410 RETURN();
411}
412#else
413void op_mult (void)
414{
415 CALL_FROM_TB0(do_mult);
416 RETURN();
417}
418
419void op_multu (void)
420{
421 CALL_FROM_TB0(do_multu);
422 RETURN();
423}
424
425void op_madd (void)
426{
427 CALL_FROM_TB0(do_madd);
428 RETURN();
429}
430
431void op_maddu (void)
432{
433 CALL_FROM_TB0(do_maddu);
434 RETURN();
435}
436
437void op_msub (void)
438{
439 CALL_FROM_TB0(do_msub);
440 RETURN();
441}
442
443void op_msubu (void)
444{
445 CALL_FROM_TB0(do_msubu);
446 RETURN();
447}
448#endif
449
450/* Conditional moves */
451void op_movn (void)
452{
453 if (T1 != 0)
454 env->gpr[PARAM1] = T0;
455 RETURN();
456}
457
458void op_movz (void)
459{
460 if (T1 == 0)
461 env->gpr[PARAM1] = T0;
462 RETURN();
463}
464
465/* Tests */
466#define OP_COND(name, cond) \
467void glue(op_, name) (void) \
468{ \
469 if (cond) { \
470 T0 = 1; \
471 } else { \
472 T0 = 0; \
473 } \
474 RETURN(); \
475}
476
477OP_COND(eq, T0 == T1);
478OP_COND(ne, T0 != T1);
479OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
480OP_COND(geu, T0 >= T1);
481OP_COND(lt, (int32_t)T0 < (int32_t)T1);
482OP_COND(ltu, T0 < T1);
483OP_COND(gez, (int32_t)T0 >= 0);
484OP_COND(gtz, (int32_t)T0 > 0);
485OP_COND(lez, (int32_t)T0 <= 0);
486OP_COND(ltz, (int32_t)T0 < 0);
487
488/* Branchs */
489//#undef USE_DIRECT_JUMP
490#define EIP env->PC
491
492/* Branch to register */
493void op_save_breg_target (void)
494{
495 env->btarget = T2;
496}
497
498void op_restore_breg_target (void)
499{
500 T2 = env->btarget;
501}
502
503void op_breg (void)
504{
505 env->PC = T2;
506 RETURN();
507}
508
509/* Unconditional branch */
510void op_branch (void)
511{
512 JUMP_TB(branch, PARAM1, 0, PARAM2);
513 RETURN();
514}
515
516void op_save_btarget (void)
517{
518 env->btarget = PARAM1;
519 RETURN();
520}
521
522/* Conditional branch */
523void op_set_bcond (void)
524{
525 T2 = T0;
526 RETURN();
527}
528
529void op_save_bcond (void)
530{
531 env->bcond = T2;
532 RETURN();
533}
534
535void op_restore_bcond (void)
536{
537 T2 = env->bcond;
538 RETURN();
539}
540
541void op_bcond (void)
542{
543 if (T2) {
544 JUMP_TB(bcond, PARAM1, 0, PARAM2);
545 } else {
546 JUMP_TB(bcond, PARAM1, 1, PARAM3);
547 }
548 RETURN();
549}
550
551/* Likely branch (used to skip the delay slot) */
552void op_blikely (void)
553{
554 /* If the test is false, skip the delay slot */
555 if (T2 == 0) {
556 env->hflags = PARAM3;
557 JUMP_TB(blikely, PARAM1, 1, PARAM2);
558 }
559 RETURN();
560}
561
562/* CP0 functions */
563void op_mfc0 (void)
564{
565 CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
566 RETURN();
567}
568
569void op_mtc0 (void)
570{
571 CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
572 RETURN();
573}
574
575#if defined(MIPS_USES_R4K_TLB)
576void op_tlbwi (void)
577{
578 CALL_FROM_TB0(do_tlbwi);
579 RETURN();
580}
581
582void op_tlbwr (void)
583{
584 CALL_FROM_TB0(do_tlbwr);
585 RETURN();
586}
587
588void op_tlbp (void)
589{
590 CALL_FROM_TB0(do_tlbp);
591 RETURN();
592}
593
594void op_tlbr (void)
595{
596 CALL_FROM_TB0(do_tlbr);
597 RETURN();
598}
599#endif
600
601/* Specials */
602void op_pmon (void)
603{
604 CALL_FROM_TB1(do_pmon, PARAM1);
605}
606
607void op_trap (void)
608{
609 if (T0) {
610 CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
611 }
612 RETURN();
613}
614
615void op_set_lladdr (void)
616{
617 env->CP0_LLAddr = T2;
618}
619
620void debug_eret (void);
621void op_eret (void)
622{
623 CALL_FROM_TB0(debug_eret);
51e11d9e 624 if (env->hflags & MIPS_HFLAG_ERL) {
6af0bf9c 625 env->PC = env->CP0_ErrorEPC;
51e11d9e
FB
626 env->hflags &= ~MIPS_HFLAG_ERL;
627 } else {
6af0bf9c 628 env->PC = env->CP0_EPC;
51e11d9e
FB
629 env->hflags &= ~MIPS_HFLAG_EXL;
630 }
6af0bf9c
FB
631 env->CP0_LLAddr = 1;
632}
633
634void op_deret (void)
635{
636 CALL_FROM_TB0(debug_eret);
637 env->PC = env->CP0_DEPC;
638}
639
640void op_save_state (void)
641{
642 env->hflags = PARAM1;
643 RETURN();
644}
645
646void op_save_pc (void)
647{
648 env->PC = PARAM1;
649 RETURN();
650}
651
652void op_raise_exception (void)
653{
654 CALL_FROM_TB1(do_raise_exception, PARAM1);
655 RETURN();
656}
657
658void op_raise_exception_err (void)
659{
660 CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
661 RETURN();
662}
663
664void op_exit_tb (void)
665{
666 EXIT_TB();
667}
668