hppa: specify target_phys_bits in configure script
[qemu/hppa.git] / target-hppa / op_helper.c
blobadbda7b4d3d46f155537f92ce45d408e9c942375
1 /*
2 * HPPA emulation helpers
4 * Copyright (c) 2005-2007 Stuart Brady <stuart.brady@gmail.com>
5 * Copyright (c) 2007 Randolph Chung <tausq@debian.org>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
22 #include "exec.h"
23 #include "helpers.h"
25 #if !defined(CONFIG_USER_ONLY)
27 #define MMUSUFFIX _mmu
29 #define SHIFT 0
30 #include "softmmu_template.h"
32 #define SHIFT 1
33 #include "softmmu_template.h"
35 #define SHIFT 2
36 #include "softmmu_template.h"
38 #define SHIFT 3
39 #include "softmmu_template.h"
41 /* XXX: tempo */
42 void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
44 CPUState *saved_env;
45 int ret;
46 target_phys_addr_t phys_addr;
47 int prot;
49 /* XXX: hack to restore env in all cases, even if not called from
50 generated code */
51 saved_env = env;
52 env = cpu_single_env;
54 /* XXX: flat mapping for the moment... */
55 phys_addr = addr;
56 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
57 ret = tlb_set_page(env, addr & TARGET_PAGE_MASK, phys_addr, prot, mmu_idx, 1);
59 env = saved_env;
62 #endif
64 #if 0
65 void OPPROTO op_ldcw_raw(void)
67 /* FIXME - should be atomic */
68 T1 = ldl_raw((void *)T0);
69 stl_raw((void *)T0, 0);
72 void OPPROTO op_ldw_phys(void)
74 /* FIXME - T0 contains a physical address */
75 T1 = ldl_raw((void *)T0);
78 void OPPROTO op_stw_phys(void)
80 /* FIXME - T0 contains a physical address */
81 stl_raw((void *)T0, T1);
84 void OPPROTO op_debug(void)
86 raise_exception(EXCP_DEBUG);
89 /* System operations */
90 void OPPROTO op_break(void)
92 raise_exception(EXCP_BREAK);
95 void OPPROTO op_check_priv0(void)
97 if (env->priv_level != 0)
98 raise_exception(EXCP_PRIVOP);
101 void OPPROTO op_check_int_timer_priv(void)
103 /* secure interval timer */
104 if ((env->psw & PSW_S) && env->priv_level != 0)
105 raise_exception(EXCP_PRIVOP);
108 void OPPROTO op_sync(void)
112 void OPPROTO op_syncdma(void)
116 void OPPROTO op_rfi(void)
118 env->psw = env->cr[22]; /* ipsw */
119 env->iaoq[0] = env->cr[18]; /* iiaoq */
120 env->iaoq[1] = env->iiaoq_back;
121 env->iasq[0] = env->cr[17]; /* iiasq */
122 env->iasq[1] = env->iiasq_back;
125 void OPPROTO op_restore_shadow(void)
127 /* restore shadow registers */
128 env->gr[1] = env->shr[0];
129 env->gr[8] = env->shr[1];
130 env->gr[9] = env->shr[2];
131 env->gr[16] = env->shr[3];
132 env->gr[17] = env->shr[4];
133 env->gr[24] = env->shr[5];
134 env->gr[25] = env->shr[6];
137 void OPPROTO op_ssm(void)
139 T0 = env->psw & (PSW_G | PSW_F | PSW_R | PSW_Q | PSW_P | PSW_D | PSW_I);
141 if (PARAM1 & (1 << 0))
142 env->psw |= PSW_I;
143 if (PARAM1 & (1 << 1))
144 env->psw |= PSW_D;
145 if (PARAM1 & (1 << 2))
146 env->psw |= PSW_P;
147 if (PARAM1 & (1 << 4))
148 env->psw |= PSW_R;
149 if (PARAM1 & (1 << 5))
150 env->psw |= PSW_F;
151 if (PARAM1 & (1 << 6))
152 env->psw |= PSW_G;
155 void OPPROTO op_rsm(void)
157 T0 = env->psw & (PSW_G | PSW_F | PSW_R | PSW_Q | PSW_P | PSW_D | PSW_I);
159 if (PARAM1 & (1 << 0))
160 env->psw &= ~PSW_I;
161 if (PARAM1 & (1 << 1))
162 env->psw &= ~PSW_D;
163 if (PARAM1 & (1 << 2))
164 env->psw &= ~PSW_P;
165 if (PARAM1 & (1 << 4))
166 env->psw &= ~PSW_R;
167 if (PARAM1 & (1 << 5))
168 env->psw &= ~PSW_F;
169 if (PARAM1 & (1 << 6))
170 env->psw &= ~PSW_G;
173 void OPPROTO op_mtsm(void)
175 env->psw = env->psw & ~(PSW_G | PSW_F | PSW_R | PSW_Q | PSW_P | PSW_D | PSW_I);
176 env->psw |= T0 & (PSW_G | PSW_F | PSW_R | PSW_Q | PSW_P | PSW_D | PSW_I);
178 #endif
180 /* computation instructions... page 169 PA1.1 specification */
182 /* TODO: lazy PSW */
183 target_ulong helper_add_cc(target_ulong t0, target_ulong t1)
185 target_ulong carry;
186 target_ulong res;
188 res = t0 + t1;
190 /* calculate carry flags */
191 carry = (t0 & t1) | ((t0 | t1) & ~res);
192 /* extract the MSB from each nibble */
193 /* axxxbxxxcxxxdxxxexxxfxxxgxxxhxxx */
194 carry >>= 3; /* 000axxxbxxxcxxxdxxxexxxfxxxgxxxh */
195 carry &= 0x11111111; /* 000a000b000c000d000e000f000g000h */
196 carry |= carry >> 3; /* 000a00ab00bc00cd00de00ef00fg00gh */
197 carry &= 0x03030303; /* 000000ab000000cd000000ef000000gh */
198 carry |= carry >> 6; /* 000000ab0000abcd000000ef0000efgh */
199 carry &= 0x000f000f; /* 000000000000abcd000000000000efgh */
200 carry |= carry >> 12; /* 000000000000abcd00000000abcdefgh */
201 carry &= 0x000000ff; /* 000000000000000000000000abcdefgh */
203 env->psw &= ~PSW_CB;
204 env->psw |= carry << PSW_CB_SHIFT;
206 return res;
209 /* TODO: lazy PSW */
210 target_ulong helper_addc_cc(target_ulong t0, target_ulong t1)
212 target_ulong carry;
213 target_ulong res;
215 res = t0 + t1;
217 /* add the carry */
218 if (env->psw & PSW_CB7) {
219 res += 1;
222 /* calculate carry flags */
223 carry = (t0 & t1) | ((t0 | t1) & ~res);
224 /* axxxbxxxcxxxdxxxexxxfxxxgxxxhxxx */
225 carry >>= 3; /* 000axxxbxxxcxxxdxxxexxxfxxxgxxxh */
226 carry &= 0x11111111; /* 000a000b000c000d000e000f000g000h */
227 carry |= carry >> 3; /* 000a00ab00bc00cd00de00ef00fg00gh */
228 carry &= 0x03030303; /* 000000ab000000cd000000ef000000gh */
229 carry |= carry >> 6; /* 000000ab0000abcd000000ef0000efgh */
230 carry &= 0x000f000f; /* 000000000000abcd000000000000efgh */
231 carry |= carry >> 12; /* 000000000000abcd00000000abcdefgh */
232 carry &= 0x000000ff; /* 000000000000000000000000abcdefgh */
234 env->psw &= ~PSW_CB;
235 env->psw |= carry << PSW_CB_SHIFT;
237 return res;
240 /* TODO */
241 /* gen_op_add_T1_imm(1) -- for ADDC and ADDCO */
242 /* overflow trap for ADDO */
243 /* set condition flags */
244 /* set nullify if condition met */
246 #if 0
247 void OPPROTO op_comclr_T1_T0(void)
249 /* T0 - T1; */
250 T0 = 0;
253 void OPPROTO op_next_insn(void)
255 env->iaoq[0] = env->iaoq[1];
256 env->iasq[0] = env->iasq[1];
257 env->iaoq[1] += 4;
260 void OPPROTO op_addit_T0(void)
262 /* XXX */
265 void OPPROTO op_addito_T0(void)
267 /* XXX */
270 void OPPROTO op_undef_insn(void)
272 /* undefined; let's kill the process so that we can easily identify
273 * any incorrect insn decoding
275 int *p = NULL;
276 T0 = *p;
279 void OPPROTO op_ill_insn(void)
281 raise_exception(EXCP_ILLEGAL);
284 void OPPROTO op_sub_T1_T0_cc(void)
286 /* TODO: lazy PSW */
287 target_ulong borrow;
288 target_ulong tmp;
290 tmp = T0;
291 T0 -= T1;
293 /* calculate carry/borrow flags */
294 borrow = (~tmp & T1) | (~(tmp ^ T1) & T0);
295 /* axxxbxxxcxxxdxxxexxxfxxxgxxxhxxx */
296 borrow >>= 3; /* 000axxxbxxxcxxxdxxxexxxfxxxgxxxh */
297 borrow &= 0x11111111; /* 000a000b000c000d000e000f000g000h */
298 borrow |= borrow >> 3; /* 000a00ab00bc00cd00de00ef00fg00gh */
299 borrow &= 0x03030303; /* 000000ab000000cd000000ef000000gh */
300 borrow |= borrow >> 6; /* 000000ab0000abcd000000ef0000efgh */
301 borrow &= 0x000f000f; /* 000000000000abcd000000000000efgh */
302 borrow |= borrow >> 12; /* 000000000000abcd00000000abcdefgh */
303 borrow &= 0x000000ff; /* 000000000000000000000000abcdefgh */
305 env->psw &= ~PSW_CB;
306 env->psw |= ~borrow << PSW_CB_SHIFT;
309 void OPPROTO op_subb_T1_T0_cc(void)
311 /* TODO: lazy PSW */
312 target_ulong borrow;
313 target_ulong tmp;
315 tmp = T0;
316 T0 -= T1;
318 /* subtract the borrow */
319 if (!(env->psw & PSW_CB7)) {
320 T0 -= 1;
323 /* calculate carry/borrow flags */
324 borrow = (~tmp & T1) | (~(tmp ^ T1) & T0);
325 /* axxxbxxxcxxxdxxxexxxfxxxgxxxhxxx */
326 borrow >>= 3; /* 000axxxbxxxcxxxdxxxexxxfxxxgxxxh */
327 borrow &= 0x11111111; /* 000a000b000c000d000e000f000g000h */
328 borrow |= borrow >> 3; /* 000a00ab00bc00cd00de00ef00fg00gh */
329 borrow &= 0x03030303; /* 000000ab000000cd000000ef000000gh */
330 borrow |= borrow >> 6; /* 000000ab0000abcd000000ef0000efgh */
331 borrow &= 0x000f000f; /* 000000000000abcd000000000000efgh */
332 borrow |= borrow >> 12; /* 000000000000abcd00000000abcdefgh */
333 borrow &= 0x000000ff; /* 000000000000000000000000abcdefgh */
335 env->psw &= ~PSW_CB;
336 env->psw |= ~borrow << PSW_CB_SHIFT;
339 void OPPROTO op_ds_T1_T0(void)
341 /* XXX */
344 void OPPROTO op_uxor_T1_T0(void)
346 /* XXX */
349 void OPPROTO op_uaddcm_T1_T0(void)
351 /* XXX */
352 /* store carry in T2 */
355 void OPPROTO op_dcor_T0(void)
357 T0 -= ((((env->psw & PSW_CB7) ? 0 : 6) << 4) |
358 ((((env->psw & PSW_CB6) ? 0 : 6) << 4) |
359 ((((env->psw & PSW_CB5) ? 0 : 6) << 4) |
360 ((((env->psw & PSW_CB4) ? 0 : 6) << 4) |
361 ((((env->psw & PSW_CB3) ? 0 : 6) << 4) |
362 ((((env->psw & PSW_CB2) ? 0 : 6) << 4) |
363 ((((env->psw & PSW_CB1) ? 0 : 6) << 4) |
364 ((((env->psw & PSW_CB0) ? 0 : 6))))))))));
367 void OPPROTO op_idcor_T0(void)
369 T0 += ((((env->psw & PSW_CB7) ? 6 : 0) << 4) |
370 ((((env->psw & PSW_CB6) ? 6 : 0) << 4) |
371 ((((env->psw & PSW_CB5) ? 6 : 0) << 4) |
372 ((((env->psw & PSW_CB4) ? 6 : 0) << 4) |
373 ((((env->psw & PSW_CB3) ? 6 : 0) << 4) |
374 ((((env->psw & PSW_CB2) ? 6 : 0) << 4) |
375 ((((env->psw & PSW_CB1) ? 6 : 0) << 4) |
376 ((((env->psw & PSW_CB0) ? 6 : 0))))))))));
379 /* Shift/deposit insns */
380 void OPPROTO op_shrpw_cc(void)
382 /* INPUT: T0 = shift amount, T1 and T2 = register pair values */
383 /* OUTPUT: T0 */
384 T0 &= 0x1f;
386 if (T0 == 0)
387 T0 = T2; /* avoid "<< 32" with undefined result */
388 else
389 T0 = (T1 << (32 - T0)) | (T2 >> T0);
390 FORCE_RET();
393 void OPPROTO op_extrw_cc(void)
395 /* INPUT: T0 = shift pos, T1 = shift len, T2 = in value */
396 /* OUTPUT: T0 */
399 void OPPROTO op_depw_cc(void)
401 /* INPUT: T0 = shift pos, T1 = shift len, T2 = in value */
402 /* OUTPUT: T0 */
405 void OPPROTO op_save_pc(void)
407 env->iaoq[0] = PARAM1;
408 env->iaoq[1] = PARAM2;
411 /* Compare operations */
413 #define signed_overflow_add(op1, op2, res) \
414 (!!(((op1 ^ op2 ^ ~0) & (op1 ^ res)) >> 31))
416 #define signed_overflow_sub(op1, op2, res) \
417 (!!(((op1 ^ op2) & (op1 ^ res)) >> 31))
419 void OPPROTO op_eval_never(void)
421 T2 = 0;
424 void OPPROTO op_eval_always(void)
426 T2 = 1;
429 /* Addition conditions:
430 * See table 5-4 in PA1.1 Specification
433 /* = */
434 void OPPROTO op_eval_add_eq(void)
436 target_ulong res = T0 + T1;
437 T2 = (res == 0);
440 /* < */
441 void OPPROTO op_eval_add_slt(void)
443 target_long res = T0 + T1;
444 T2 = ((res < 0) != signed_overflow_add(T0, T1, res));
447 /* <= */
448 void OPPROTO op_eval_add_slteq(void)
450 target_long res = T0 + T1;
451 T2 = ((res == 0) || ((res < 0) != signed_overflow_add(T0, T1, res)));
454 /* nuv */
455 void OPPROTO op_eval_add_nuv(void)
457 target_ulong res = T0 + T1;
458 T2 = (res >= T0);
461 /* znv */
462 void OPPROTO op_eval_add_znv(void)
464 target_ulong res = T0 + T1;
465 T2 = ((res == 0) || (res >= T0));
468 /* sv */
469 void OPPROTO op_eval_add_sv(void)
471 target_long res = T0 + T1;
472 T2 = signed_overflow_add(T0, T1, res);
475 /* od */
476 void OPPROTO op_eval_add_od(void)
478 target_ulong res = T0 + T1;
479 T2 = (res & 1);
482 /* Addition conditions with carry */
484 /* = */
485 void OPPROTO op_eval_addc_eq(void)
487 target_ulong res = T0 + T1 + !!(env->psw & PSW_CB7);
488 T2 = (res == 0);
491 /* < */
492 void OPPROTO op_eval_addc_slt(void)
494 target_long res = T0 + T1 + !!(env->psw & PSW_CB7);
495 T2 = ((res < 0) != signed_overflow_add(T0, T1, res));
498 /* <= */
499 void OPPROTO op_eval_addc_slteq(void)
501 target_long res = T0 + T1 + !!(env->psw & PSW_CB7);
502 T2 = ((res == 0) || ((res < 0) != signed_overflow_add(T0, T1, res)));
505 /* nuv */
506 void OPPROTO op_eval_addc_nuv(void)
508 target_ulong res = T0 + T1 + !!(env->psw & PSW_CB7);
509 if (env->psw & PSW_CB7)
510 T2 = (res > T0);
511 else
512 T2 = (res >= T0);
513 FORCE_RET();
516 /* znv */
517 void OPPROTO op_eval_addc_znv(void)
519 target_ulong res = T0 + T1 + !!(env->psw & PSW_CB7);
520 if (env->psw & PSW_CB7)
521 T2 = ((res == 0) || (res > T0));
522 else
523 T2 = ((res == 0) || (res >= T0));
524 FORCE_RET();
527 /* sv */
528 void OPPROTO op_eval_addc_sv(void)
530 target_long res = T0 + T1 + !!(env->psw & PSW_CB7);
531 T2 = signed_overflow_add(T0, T1, res);
534 /* od */
535 void OPPROTO op_eval_addc_od(void)
537 target_ulong res = T0 + T1 + !!(env->psw & PSW_CB7);
538 T2 = (res & 1);
541 /* Compare/subtract conditions:
542 * See table 5-3 in PA1.1 Specification
545 /* = */
546 void OPPROTO op_eval_sub_eq(void)
548 target_ulong res = T0 - T1;
549 T2 = (res == 0);
552 /* < */
553 void OPPROTO op_eval_sub_slt(void)
555 target_long res = T0 - T1;
556 T2 = ((res < 0) != signed_overflow_sub(T0, T1, res));
559 /* <= */
560 void OPPROTO op_eval_sub_slteq(void)
562 target_long res = T0 - T1;
563 T2 = ((res == 0) || ((res < 0) != signed_overflow_sub(T0, T1, res)));
566 /* << */
567 void OPPROTO op_eval_sub_ult(void)
569 target_ulong res = T0 - T1;
570 T2 = (res < 0);
573 /* <<= */
574 void OPPROTO op_eval_sub_ulteq(void)
576 target_ulong res = T0 - T1;
577 T2 = ((res == 0) || (res < T0));
580 /* sv */
581 void OPPROTO op_eval_sub_sv(void)
583 target_long res = T0 - T1;
584 T2 = signed_overflow_sub(T0, T1, res);
587 /* od */
588 void OPPROTO op_eval_sub_od(void)
590 target_long res = T0 - T1;
591 T2 = (res & 1);
594 /* Compare operations with borrow */
596 /* = */
597 void OPPROTO op_eval_subb_eq(void)
599 target_ulong res = T0 - T1 - !(env->psw & PSW_CB7);
600 T2 = (res == 0);
603 /* < */
604 void OPPROTO op_eval_subb_slt(void)
606 target_long res = T0 - T1 - !(env->psw & PSW_CB7);
607 T2 = ((res < 0) != signed_overflow_sub(T0, T1, res));
610 /* <= */
611 void OPPROTO op_eval_subb_slteq(void)
613 target_long res = T0 - T1 - !(env->psw & PSW_CB7);
614 T2 = ((res == 0) || ((res < 0) != signed_overflow_sub(T0, T1, res)));
617 /* << */
618 void OPPROTO op_eval_subb_ult(void)
620 target_ulong res = T0 - T1 - !(env->psw & PSW_CB7);
621 T2 = (res < 0);
624 /* <<= */
625 void OPPROTO op_eval_subb_ulteq(void)
627 target_ulong res = T0 - T1 - !(env->psw & PSW_CB7);
628 T2 = ((res == 0) || (res < T0));
631 /* sv */
632 void OPPROTO op_eval_subb_sv(void)
634 target_long res = T0 - T1 - !(env->psw & PSW_CB7);
635 T2 = signed_overflow_sub(T0, T1, res);
638 /* od */
639 void OPPROTO op_eval_subb_od(void)
641 target_long res = T0 - T1 - !(env->psw & PSW_CB7);
642 T2 = (res & 1);
645 /* Logical conditions:
646 * See table 5-5 in PA1.1 Specification
649 /* = */
650 void OPPROTO op_eval_log_eq(void)
652 T2 = (T0 == 0);
655 /* < */
656 void OPPROTO op_eval_log_slt(void)
658 T2 = ((target_long)T0 < 0);
661 /* <= */
662 void OPPROTO op_eval_log_slteq(void)
664 T2 = ((target_long)T1 <= 0);
667 /* od */
668 void OPPROTO op_eval_log_od(void)
670 T2 = (T0 & 1);
673 /* Unit conditions:
674 * See table 5-6 in PA1.1 Specification
677 void OPPROTO op_eval_unit_sbz(void)
679 T2 = ((T0 - 0x01010101) & ~T0 & 0x80808080);
682 void OPPROTO op_eval_unit_shz(void)
684 T2 = ((T0 - 0x00010001) & ~T0 & 0x80008000);
687 void OPPROTO op_eval_unit_sdc(void)
689 T2 &= 0x88888888;
692 void OPPROTO op_eval_unit_sbc(void)
694 T2 &= 0x80808080;
697 void OPPROTO op_eval_unit_shc(void)
699 T2 &= 0x80008000;
702 /* Shift/extract/deposit conditions
703 * See table 5-7 in PA1.1 Specification
706 /* <> */
707 void OPPROTO op_eval_log_neq(void)
709 T2 = (T0 != 0);
712 /* >= */
713 void OPPROTO op_eval_log_sgteq(void)
715 T2 = ((target_long)T0 >= 0);
718 /* ev */
719 void OPPROTO op_eval_log_ev(void)
721 T2 = !(T0 & 1);
724 /* ------ */
726 void OPPROTO op_jmp_im(void)
728 env->iaoq[0] = (uint32_t)PARAM1;
729 env->iaoq[1] = env->iaoq[0] + 4;
732 void OPPROTO op_jnz_T2_label(void)
734 if (T2)
735 GOTO_LABEL_PARAM(1);
736 FORCE_RET();
739 void OPPROTO op_jz_T2_label(void)
741 if (!T2)
742 GOTO_LABEL_PARAM(1);
743 FORCE_RET();
745 #endif