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
25 #if !defined(CONFIG_USER_ONLY)
27 #define MMUSUFFIX _mmu
30 #include "softmmu_template.h"
33 #include "softmmu_template.h"
36 #include "softmmu_template.h"
39 #include "softmmu_template.h"
42 void tlb_fill(target_ulong addr
, int is_write
, int mmu_idx
, void *retaddr
)
46 target_phys_addr_t phys_addr
;
49 /* XXX: hack to restore env in all cases, even if not called from
54 /* XXX: flat mapping for the moment... */
56 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
57 ret
= tlb_set_page(env
, addr
& TARGET_PAGE_MASK
, phys_addr
, prot
, mmu_idx
, 1);
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))
143 if (PARAM1
& (1 << 1))
145 if (PARAM1
& (1 << 2))
147 if (PARAM1
& (1 << 4))
149 if (PARAM1
& (1 << 5))
151 if (PARAM1
& (1 << 6))
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))
161 if (PARAM1
& (1 << 1))
163 if (PARAM1
& (1 << 2))
165 if (PARAM1
& (1 << 4))
167 if (PARAM1
& (1 << 5))
169 if (PARAM1
& (1 << 6))
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
);
180 /* computation instructions... page 169 PA1.1 specification */
183 target_ulong
helper_add_cc(target_ulong t0
, target_ulong 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 */
204 env
->psw
|= carry
<< PSW_CB_SHIFT
;
210 target_ulong
helper_addc_cc(target_ulong t0
, target_ulong t1
)
218 if (env
->psw
& PSW_CB7
) {
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 */
235 env
->psw
|= carry
<< PSW_CB_SHIFT
;
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 */
247 void OPPROTO
op_comclr_T1_T0(void)
253 void OPPROTO
op_next_insn(void)
255 env
->iaoq
[0] = env
->iaoq
[1];
256 env
->iasq
[0] = env
->iasq
[1];
260 void OPPROTO
op_addit_T0(void)
265 void OPPROTO
op_addito_T0(void)
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
279 void OPPROTO
op_ill_insn(void)
281 raise_exception(EXCP_ILLEGAL
);
284 void OPPROTO
op_sub_T1_T0_cc(void)
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 */
306 env
->psw
|= ~borrow
<< PSW_CB_SHIFT
;
309 void OPPROTO
op_subb_T1_T0_cc(void)
318 /* subtract the borrow */
319 if (!(env
->psw
& PSW_CB7
)) {
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 */
336 env
->psw
|= ~borrow
<< PSW_CB_SHIFT
;
339 void OPPROTO
op_ds_T1_T0(void)
344 void OPPROTO
op_uxor_T1_T0(void)
349 void OPPROTO
op_uaddcm_T1_T0(void)
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 */
387 T0
= T2
; /* avoid "<< 32" with undefined result */
389 T0
= (T1
<< (32 - T0
)) | (T2
>> T0
);
393 void OPPROTO
op_extrw_cc(void)
395 /* INPUT: T0 = shift pos, T1 = shift len, T2 = in value */
399 void OPPROTO
op_depw_cc(void)
401 /* INPUT: T0 = shift pos, T1 = shift len, T2 = in value */
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)
424 void OPPROTO
op_eval_always(void)
429 /* Addition conditions:
430 * See table 5-4 in PA1.1 Specification
434 void OPPROTO
op_eval_add_eq(void)
436 target_ulong res
= T0
+ T1
;
441 void OPPROTO
op_eval_add_slt(void)
443 target_long res
= T0
+ T1
;
444 T2
= ((res
< 0) != signed_overflow_add(T0
, T1
, res
));
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
)));
455 void OPPROTO
op_eval_add_nuv(void)
457 target_ulong res
= T0
+ T1
;
462 void OPPROTO
op_eval_add_znv(void)
464 target_ulong res
= T0
+ T1
;
465 T2
= ((res
== 0) || (res
>= T0
));
469 void OPPROTO
op_eval_add_sv(void)
471 target_long res
= T0
+ T1
;
472 T2
= signed_overflow_add(T0
, T1
, res
);
476 void OPPROTO
op_eval_add_od(void)
478 target_ulong res
= T0
+ T1
;
482 /* Addition conditions with carry */
485 void OPPROTO
op_eval_addc_eq(void)
487 target_ulong res
= T0
+ T1
+ !!(env
->psw
& PSW_CB7
);
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
));
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
)));
506 void OPPROTO
op_eval_addc_nuv(void)
508 target_ulong res
= T0
+ T1
+ !!(env
->psw
& PSW_CB7
);
509 if (env
->psw
& PSW_CB7
)
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
));
523 T2
= ((res
== 0) || (res
>= T0
));
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
);
535 void OPPROTO
op_eval_addc_od(void)
537 target_ulong res
= T0
+ T1
+ !!(env
->psw
& PSW_CB7
);
541 /* Compare/subtract conditions:
542 * See table 5-3 in PA1.1 Specification
546 void OPPROTO
op_eval_sub_eq(void)
548 target_ulong res
= T0
- T1
;
553 void OPPROTO
op_eval_sub_slt(void)
555 target_long res
= T0
- T1
;
556 T2
= ((res
< 0) != signed_overflow_sub(T0
, T1
, res
));
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
)));
567 void OPPROTO
op_eval_sub_ult(void)
569 target_ulong res
= T0
- T1
;
574 void OPPROTO
op_eval_sub_ulteq(void)
576 target_ulong res
= T0
- T1
;
577 T2
= ((res
== 0) || (res
< T0
));
581 void OPPROTO
op_eval_sub_sv(void)
583 target_long res
= T0
- T1
;
584 T2
= signed_overflow_sub(T0
, T1
, res
);
588 void OPPROTO
op_eval_sub_od(void)
590 target_long res
= T0
- T1
;
594 /* Compare operations with borrow */
597 void OPPROTO
op_eval_subb_eq(void)
599 target_ulong res
= T0
- T1
- !(env
->psw
& PSW_CB7
);
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
));
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
)));
618 void OPPROTO
op_eval_subb_ult(void)
620 target_ulong res
= T0
- T1
- !(env
->psw
& PSW_CB7
);
625 void OPPROTO
op_eval_subb_ulteq(void)
627 target_ulong res
= T0
- T1
- !(env
->psw
& PSW_CB7
);
628 T2
= ((res
== 0) || (res
< T0
));
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
);
639 void OPPROTO
op_eval_subb_od(void)
641 target_long res
= T0
- T1
- !(env
->psw
& PSW_CB7
);
645 /* Logical conditions:
646 * See table 5-5 in PA1.1 Specification
650 void OPPROTO
op_eval_log_eq(void)
656 void OPPROTO
op_eval_log_slt(void)
658 T2
= ((target_long
)T0
< 0);
662 void OPPROTO
op_eval_log_slteq(void)
664 T2
= ((target_long
)T1
<= 0);
668 void OPPROTO
op_eval_log_od(void)
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)
692 void OPPROTO
op_eval_unit_sbc(void)
697 void OPPROTO
op_eval_unit_shc(void)
702 /* Shift/extract/deposit conditions
703 * See table 5-7 in PA1.1 Specification
707 void OPPROTO
op_eval_log_neq(void)
713 void OPPROTO
op_eval_log_sgteq(void)
715 T2
= ((target_long
)T0
>= 0);
719 void OPPROTO
op_eval_log_ev(void)
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)
739 void OPPROTO
op_jz_T2_label(void)